Java中的自定义注解
Author 阿飞
@date2016-11-01
1.1 注解简介
注解实际上是接口,我们可以把注解视为一种规范。
1.2 元注解
元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它annotation类型作说明。Java5.0定义的元注解:
1.@Target,
2.@Retention,
3.@Documented,
4.@Inherited
这些类型和它们所支持的类在java.lang.annotation包中可以找到。对于每一个注解的作用和参数的可选值以及解释,可以参考JDK源码。
1.3自定义注解
自定义注解的基本开发流程是:
下面笔者以自己初步开发的一个验证对象属性值的自定义注解为例,详细说明一下:
1.3.1注解定义
注解使用@interface标志,同时需要元注解的协助方可实际应用。使用了@interface标志后,在编译阶段,Java编译器会使该注解接口继承自java.lang.annotation.Annotation接口。请看一下代码的字节码便可知晓:
package com.xtu.annotion.userDefined;
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;
import com.xtu.annotion.parms.ValidateAnnotionConstant;
/** * 自定义注解-验证实体属性 * * @author阿飞 * @date 2016-11-1 */ @Target(ElementType.FIELD) // 定义该注解只能用在属性上 @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ValidateAnnotion {
// 定义注解参数-名称为value // 定义注解参数有默认值时,可在使用注解时不输入该参数 // 定义注解参数没有默认值时,一定要在使用注解时输入该参数,否则编译不通过 public String value() default ValidateAnnotionConstant.VALUE_DEFAULT;
// 定义注解参数-名称为length public int length() default ValidateAnnotionConstant.LENGTH_DEFAULT;
// 定义注解参数-名称为min public int min() default ValidateAnnotionConstant.MIN_DEFAULT;
}
|
1.3.2注解处理器
注解处理器是负责具体解释注解的,它利用反射技术获取使用了注解的类实例属性,以及属性的注解信息,然后根据具体业务规则进行属性规则匹配,示例代码如下:
package com.xtu.annotion.processor;
import java.util.List; import java.lang.reflect.Field; import java.util.ArrayList;
import com.xtu.annotion.parms.ValidateAnnotionConstant; import com.xtu.annotion.userDefined.ValidateAnnotion;
/** * 验证实体属性注解处理器 * * 处理器应根据注解的定义开发 * * @author阿飞 * @date 2016-11-1 */ public class ValidateAnnotionProcessor {
/** * 注解处理方法 * * @param obj * 被注解的类实例 * @return注解处理结果(此处指属性验证结果) * @throws IllegalArgumentException * @throws IllegalAccessException */ public static List<String> process(Object obj) throws IllegalArgumentException, IllegalAccessException {
List<String> resultList = new ArrayList<String>(); if (null != obj) { Class<?> clazz = obj.getClass(); // 获取类定义的属性列表 Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { // 判断属性是否代表了指定的注解 if (field.isAnnotationPresent(ValidateAnnotion.class)) { // 获取当前属性的注解信息 ValidateAnnotion validateAnnotion = field.getAnnotation(ValidateAnnotion.class);
// 获取注解中的参数信息 String value = validateAnnotion.value(); // 获取注解中的value参数值 int len = validateAnnotion.length(); // 获取注解中的length参数值 int min = validateAnnotion.min(); // 获取注解中的min参数值 System.out.println("value = " + value + ",len = " + len + ",min = " + min); // 打开私有访问权限 field.setAccessible(true); // 处理所有参数(需要能区分哪些参数是用户书写的,此处笔者是使用注解参数的默认值来区分,定义默认值为用户不会输入的值) // 验证value参数 if (!ValidateAnnotionConstant.VALUE_DEFAULT.equals(value)) { resultList.add(validateValue(value, field, obj)); } // 验证length参数 if (ValidateAnnotionConstant.LENGTH_DEFAULT != len) { resultList.add(validateLength(len, field, obj)); } // 验证min参数 if (ValidateAnnotionConstant.MIN_DEFAULT != min) { resultList.add(validateMin(min, field, obj)); }
} } } return resultList; }
private static String validateMin(int min, Field field, Object obj) throws IllegalArgumentException, IllegalAccessException {
// 获取对象的属性值 int fieldValue = field.getInt(obj); // 验证属性值 if (fieldValue >= min) { return ValidateAnnotionConstant.SUCCESS; } // 获取属性名称 String fieldName = field.getName(); return "属性[" + fieldName + "]验证min失败!"; }
private static String validateLength(int length, Field field, Object obj) throws IllegalArgumentException, IllegalAccessException { // 获取对象的属性值 String fieldValue = (String) field.get(obj); // 验证属性值 if (null != fieldValue) { if (fieldValue.length() == length) { return ValidateAnnotionConstant.SUCCESS; } } // 获取属性名称 String fieldName = field.getName(); return "属性[" + fieldName + "]验证length失败!"; }
private static String validateValue(String value, Field field, Object obj) throws IllegalArgumentException, IllegalAccessException { // 获取对象的属性值 String fieldValue = (String) field.get(obj); // 验证属性值 if (null != fieldValue && null != value) { if (fieldValue.equals(value)) { return ValidateAnnotionConstant.SUCCESS; } } // 获取属性名称 String fieldName = field.getName(); return "属性[" + fieldName + "]验证value失败!"; }
}
|
1.3.3注解使用
定义了注解自然要使用,注解在定义时便已经确定了该注解能作用于类、接口、属性还是其它。注解的使用很简单,就是在能使用它的地方按格式
@注解名(参数名=参数值, 参数名=参数值,…)
书写即可,如下示例:
package com.xtu.annotion.entity;
import com.xtu.annotion.userDefined.ValidateAnnotion;
/** * 自定义注解的使用 * * @author阿飞 * @date 2016-11-1 */ public class User {
private String userName;
@ValidateAnnotion(length = 6) private String pwd;
@ValidateAnnotion(min = 1) private int age;
@ValidateAnnotion(value="dance",length = 5) private String hobby;
public User(String userName, String pwd,int age,String hobby) { super(); this.userName = userName; this.pwd = pwd; this.age = age; this.hobby = hobby; } }
|
1.3.4使注解起作用
完成了以上内容,还需要有一个程序调用注解处理器,才能是注解真正发挥作用,我们可以手动在需要调用注解处理器的地方调用即可,如下面代码中的ValidateAnnotionProcessor.process方法,当然,也可以使用AOP思想拦截方法统一使注解发挥作用。
package com.xtu.annotion.test;
import java.util.List;
import com.xtu.annotion.entity.User; import com.xtu.annotion.processor.ValidateAnnotionProcessor;
public class Main {
public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException { User user0 = new User("Kitty","123456",6,"dance"); User user1 = new User("Kitty","123456",0,"singi"); User user2 = new User("Kitty","123456",0,"dance"); // 调用注解处理器,使注解发挥作用 List<String> results0 = ValidateAnnotionProcessor.process(user0); List<String> results1 = ValidateAnnotionProcessor.process(user1); List<String> results2 = ValidateAnnotionProcessor.process(user2); System.out.println(results0); System.out.println(results1); System.out.println(results2); }
} // 测试结果
|
附录
参考资料:
[1]. http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html
[2]. http://www.cnblogs.com/peida/archive/2013/04/26/3038503.html