注解的工作原理
注解我们日常使用的很多,常与切面一起配合使用,非常灵活与方便,那么他的工作原理是什么呢?
1.测试类的编写
测试枚举
package cn.xxx.practice.annotations;
/**
* 操作类型
* @author dell
*
*/
public enum OperationTypeEnums {
/**
* 工作类别条件查询
*/
WORKTYPE_MATCH_QUERY("GZLB", "工作类别条件查询"),
/**
* 工作类别聚合查询
*/
WORKTYPE_AGGS_QUERY("GZLB", "工作类别聚合查询"),
/**
* 新增/修改
*/
SAVE("SAVE", "新增/修改"),
/**
* 下载
*/
DOWNLOAD("DOWNLOAD", "下载"),
/**
* 删除
*/
DELETE("DELETE", "删除"),
/**
* 查询列表
*/
LIST("LIST", "查询列表"),
/**
* 查看
*/
SHOW("SHOW", "查看详情");
/** 枚举码. 数据库名称 */
private final String code;
/** 描述信息. 实体名称 */
private final String desc;
/**
* 私有构造方法.
*/
private OperationTypeEnums(String code, String desc) {
this.code = code;
this.desc = desc;
}
public static OperationTypeEnums getBizStatus(String code) {
for (OperationTypeEnums status : OperationTypeEnums.values()) {
if (status.getCode().equals(code)) {
return status;
}
}
return null;
}
public static String getDesc(String code) {
for (OperationTypeEnums status : OperationTypeEnums.values()) {
if (status.getCode().equals(code)) {
return status.desc;
}
}
return null;
}
public String getCode() {
return code;
}
public String getDesc() {
return desc;
}
@Override
public String toString() {
return this.code;
}
}
测试注解
package cn.xxx.practice.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Author xp
* @Description 声明es的操作类型 声明参数
* @Param
* @return
**/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SearchAnnotation {
OperationTypeEnums operation();//操作
}
测试类
package cn.xxx.practice.annotations;
/**
* @ClassName: TestAnnotation
* @Description: TODO
* @author: XP
*/
public class TestAnnotation {
@SearchAnnotation(operation = OperationTypeEnums.WORKTYPE_MATCH_QUERY)
private String test;
}
通过反射的方式拿到注解对应的值
package cn.xxx.practice.annotations;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
/**
* @ClassName: AnnotationParser
* @Description: TODO
* @author: XP
*/
public class AnnotationParser {
public static void parseTypeAnnotation() throws ClassNotFoundException {
Class<?> aClass = Class.forName("cn.xxx.practice.annotations.TestAnnotation");
Field[] declaredFields = aClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
boolean annotationPresent = declaredField.isAnnotationPresent(SearchAnnotation.class);
if(annotationPresent){
SearchAnnotation annotation = declaredField.getAnnotation(SearchAnnotation.class);
System.out.println(annotation.operation().getDesc());
System.out.println(annotation.operation().getCode());
}
}
}
public static void main(String[] args) throws ClassNotFoundException {
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
parseTypeAnnotation();
}
}
2.注解的底层原理
在运行时加入参数-Djdk.proxy.ProxyGenerator.saveGeneratedFiles=treue,在运行时会保存相关的动态代理对象
如果没有作用就在调用动态代理的地方加上下面代码,会出现com.sun.proxy的包里面就是动态代理
查看$Proxy1.class,通过反射去执行我们注解的方法
而它是通过调用父类的invoke方法 这个invoke并不是反射中的invoke方法
而AnnotationInvocationHandler实现InvocationHandler
3.总结
注解的作用:
1.可以通过键值对的方式为注解属性赋值
2.注解定义了使用范围,编译器会检查注解的使用范围,将注解信息写入元素属性表。
3.运行时jvm将runtime的所有注解属性取出放入一个map中(单个class文件)
4.创建AnnotationInvocationHandler实例并传入前面的map
5.jvm使用jdk的动态代理为注解生成代理类,并初始化处理器
6.调用invoke方法,通过方法名返回注解对应的属性值