注解的工作原理

注解的工作原理

Scroll Down

注解的工作原理

注解我们日常使用的很多,常与切面一起配合使用,非常灵活与方便,那么他的工作原理是什么呢?

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的包里面就是动态代理

image.png
查看$Proxy1.class,通过反射去执行我们注解的方法
image.png
image.png
而它是通过调用父类的invoke方法 这个invoke并不是反射中的invoke方法
image.png
而AnnotationInvocationHandler实现InvocationHandler
image.png
image.png
image.png

3.总结

注解的作用:
1.可以通过键值对的方式为注解属性赋值
2.注解定义了使用范围,编译器会检查注解的使用范围,将注解信息写入元素属性表。
3.运行时jvm将runtime的所有注解属性取出放入一个map中(单个class文件)
4.创建AnnotationInvocationHandler实例并传入前面的map
5.jvm使用jdk的动态代理为注解生成代理类,并初始化处理器
6.调用invoke方法,通过方法名返回注解对应的属性值