Java中的自定义注解
Posted 孙琛斌(浮生)
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java中的自定义注解相关的知识,希望对你有一定的参考价值。
说起注解来,大家第一想到的肯定是@Controller、@Service、@Autowired、@Resources、@ResponseBody、@Transactional等,当然还有很多,例举的这些都是大家非常熟悉的。
使用过的人都知道,通过注解减少了我们很多冗余的代码量,用起来也很舒服,本文揭开注解的神秘面纱,自己动手写一个自定的注解。
前几天我写了一套Mybatis根据在实体类上配置注解的方式,自动去创建表更新表结构,那我就用这里面的其中一个注解来讲解自定义注解吧。
首先我们创建一个自定义的注解,代码如下:
package com.sunchenbin.store.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 建表的必备注解
*
* @author sunchenbin
* @version 2016年6月23日 下午6:12:48
*/
// 该注解用于方法声明
@Target(ElementType.FIELD)
// VM将在运行期也保留注释,因此可以通过反射机制读取注解的信息
@Retention(RetentionPolicy.RUNTIME)
// 将此注解包含在javadoc中
@Documented
// 允许子类继承父类中的注解
@Inherited
public @interface Column{
/**
* 字段名
*
* @return
*/
public String name();
/**
* 字段类型
*
* @return
*/
public String type();
/**
* 字段长度,默认是255
*
* @return
*/
public int length() default 255;
/**
* 小数点长度,默认是0
*
* @return
*/
public int decimalLength() default 0;
/**
* 是否为可以为null,true是可以,false是不可以,默认为true
*
* @return
*/
public boolean isNull() default true;
/**
* 是否是主键,默认false
*
* @return
*/
public boolean isKey() default false;
/**
* 是否自动递增,默认false 只有主键才能使用
*
* @return
*/
public boolean isAutoIncrement() default false;
/**
* 默认值,默认为null
*
* @return
*/
public String defaultValue() default "NULL";
}
那么@Column就是我们自定义的注解了,那么怎么用呢,当然要解释下下面这几个注解:
作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
取值(ElementType)有:
1.CONSTRUCTOR:用于描述构造器
2.FIELD:用于描述域
3.LOCAL_VARIABLE:用于描述局部变量
4.METHOD:用于描述方法
5.PACKAGE:用于描述包
6.PARAMETER:用于描述参数
7.TYPE:用于描述类、接口(包括注解类型) 或enum声明
作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)
取值(RetentionPoicy)有:
1.SOURCE:在源文件中有效(即源文件保留)
2.CLASS:在class文件中有效(即class保留)
3.RUNTIME:在运行时有效(即运行时保留)
用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。
Documented是一个标记注解,没有成员。
@Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。
如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
注意:@Inherited annotation类型是被标注过的class的子类所继承。
类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。
当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。
如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,
直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。
OK,大概就上面描述的这样,然后看下@Column在实际应用中的使用:
public class Test extends BaseModel{
private static final long serialVersionUID = 5199200306752426433L;
@Column(name = "id",type = mysqlTypeConstant.INT,length = 11,isNull=false,isKey = true,isAutoIncrement=true)
private int id;
@Column(name = "name",type = MySqlTypeConstant.VARCHAR,length = 111)
private String name;
@Column(name = "description",type = MySqlTypeConstant.TEXT,length = 100)
private String description;
@Column(name = "create_time",type = MySqlTypeConstant.DATETIME,length = 0)
private Date create_time;
@Column(name = "update_time",type = MySqlTypeConstant.DATETIME,length = 0)
private Date update_time;
@Column(name = "number",type = MySqlTypeConstant.DECIMAL,length = 5,decimalLength = 1,isNull = false)
private Long number;
@Column(name = "lifecycle",type = MySqlTypeConstant.CHAR,length = 1)
private String lifecycle;
@Column(name = "dekes",type = MySqlTypeConstant.DOUBLE,length = 5,decimalLength = 2)
private Double dekes;
}
可以看到,使用@Column是需要带参数的,参考上面自定义注解的代码,比如name,没有使用默认值,那么他就是必须设置值的,如果有设置default那么就是可以不写的。
OK,配置会配了,那么如何通过代码获取到配置呢?
看下面代码:
private void tableFieldsConstruct(Map<String, Object> mySqlTypeAndLengthMap,Class<?> clas,List<Object> newFieldList){
Field[] fields = clas.getDeclaredFields();
for (Field field : fields){
// 判断方法中是否有指定注解类型的注解
boolean hasAnnotation = field.isAnnotationPresent(Column.class);
if (hasAnnotation) {
// 根据注解类型返回方法的指定类型注解
Column column = field.getAnnotation(Column.class);
CreateTableParam param = new CreateTableParam();
param.setFieldName(column.name());
param.setFieldType(column.type().toLowerCase());
param.setFieldLength(column.length());
param.setFieldDecimalLength(column.decimalLength());
param.setFieldIsNull(column.isNull());
param.setFieldIsKey(column.isKey());
param.setFieldIsAutoIncrement(column.isAutoIncrement());
param.setFieldDefaultValue(column.defaultValue());
int length = (Integer) mySqlTypeAndLengthMap.get(column.type());
param.setFileTypeLength(length);
newFieldList.add(param);
}
}
}
上面代码参杂了一些业务逻辑,无需关系,只需要领会其精神就可以了,主要就是拿到使用注解的对象的class,比如我们Test.class,由于我们注解是写在实体类的属性上,所以我们就要获取Test.class的所有Fields,然后根据注解的类型去get一下field就得到该注解类型了,然后就可以取出你注解上设置的值了。
好了,到这里自定义注解的创建使用,示例就结束了,有问题的可以留言~~~
以上是关于Java中的自定义注解的主要内容,如果未能解决你的问题,请参考以下文章