一、基本认识
我们知道,注释是给人看的,那么注解,其实就是给“程序”看的。
jdk内部注解(1.5之后):
- @Deprecated 意思是“废弃的,过时的”
- @Override 意思是“重写、覆盖”
- @SuppressWarnings 意思是“压缩警告”
自定义注解,需要使用元注解,其为“注解的注解”,并在运行时通过反射获取并处理。
元注解:
- @Target:注解的作用目标
作用域:
CONSTRUCTOR:构造器的声明
FIELD:域声明(包括enum实例)
LOCAL_VARIABLE:局部变量声明
METHOD:方法声明
PACKAGE:包声明
PARAMETER:参数声明
TYPE:类、接口(包括注解类型)或enum声明 - @Retention:注解的生命周期
- @Documented:注解是否应当被包含在 JavaDoc 文档中
- @Inherited:是否允许子类继承该注解
二、简单使用
一个例子:
@Target({ElementType.FIELD}) // 使用范围:属性域
@Retention(RetentionPolicy.RUNTIME) // 运行时
public @interface Level {
String value () default "one"; // value默认为one
}
使用:
public class ColorLevel{
@Level // 这里取默认值,one
private String green;
@Level(value="two") // 正常设置,为two
private String yellow;
@Level("three") // 这里要注意,如果自定义注解中,第一个属性名称为value,则其可省略简写
private String red;
}
利用反射获取:
public static void main(String[] args){
ColorLevel colorLevel = new ColorLevel();
Field[] fields = colorLevel.getClass().getDeclaredFields();
for (Field field:fields) {
field.setAccessible(true);
// 获取属性上的注解
Level level = field.getAnnotation(Level.class);
if(level != null){
System.out.println("颜色:"+field.getName()+" 对应级别为:"+level.value());
}
}
}
输出结果:
颜色:green 对应级别为:one
颜色:yellow 对应级别为:two
颜色:red 对应级别为:three
三、使用场景
在实体类上标注解,用以拼接sql。
Column注解
@Inherited
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Column {
String value() default "";
}
Table注解
@Inherited
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Table {
String value() default "";
}
实体类 user.java
@Table("user")
public class User {
@Query
@Column("id")
private String id;
@Column("name")
private String name;
private String address;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
解析注解,组装sql
public static String assembleSelSQL(Object obj) throws Exception{
StringBuffer sql = new StringBuffer();
sql.append("select ");
StringBuffer sqlWhere = new StringBuffer();
sqlWhere.append(" where 1=1 ");
// 获取类上的注解
boolean isTable = obj.getClass().isAnnotationPresent(Table.class);
if (isTable) {
Field[] fields = obj.getClass().getDeclaredFields();
for (Field field:fields){
field.setAccessible(true);
// 获取属性上的注解
Column column = field.getAnnotation(Column.class);
if(column != null){
sql.append(field.getName()+",");
}
Query query = field.getAnnotation(Query.class);
if(query != null){
sqlWhere.append(" and "+field.getName()+"='"+field.get(obj)+"'");
}
}
Table table = obj.getClass().getAnnotation(Table.class);
sqlWhere.insert(0," from "+table.value()).insert(0,sql.substring(0,sql.length()-1));
}
return sqlWhere.toString();
}
使用
public static void main(String[] args){
User user = new User();
user.setId("001");
user.setName("nep");
try {
String sql = assembleSelSQL(user);
System.out.println(sql);
}catch (Exception e){
e.printStackTrace();
}
}
输出
select id,name from user where 1=1 and id='001'
总结:
从上面的例子可以看出来,通过注解,可以告诉程序,(类、方法、字段)可以做什么,如:组装sql;但是没有告诉我们,哪里可以做?试想,如果结合aop(动态代理)技术,来告诉我们哪里可以做,那么,我们是不是可以“为所欲为”了呢?
比如:
1.自定义简化版orm框架;
2.自定义简化版日志框架;
3.参数校验、过滤等。
下一篇,我们结合 注解+AOP技术,来一一实现。