spring 注解详解

https://www.cnblogs.com/youzhibing/p/11031216.html(转 @Autowired工作原理)
注解(Annotation)不是程序本身,但是可以对程序作出解释,同时注解还可以让其他程序读取。我们可以把注解加在包(package)、类(class)、方法(method)和变量(field)的上面。
    注解是一个接口,一个继承自Annotation的接口。 里面每一个属性,其实就是接口的一个抽象方法

一、内置注解


1、@Override
定义在 java.lang.Override 中 , 此注释只适用于修辞方法 , 表示一个方法声明打算 重写超类中的另一个方法声明,简单来说就是子类在重写父类方法的时候可以加上这个注解。

2、@Deprecated
定义在java.lang.Deprecated中 , 此注释可以用于修辞方法 , 属性 , 类 , 表示不 鼓励程序员使用这样的元素 , 通常是因为它很危险或者存在更好的选择 。即是此方法已经过时,不推使用。

3、@SuppressWarnings
定义在 java.lang.SuppressWarnings 中,用来抑制编译时的警告信息,与前两个注释有所不同,你需要添加一个参数才能正确使用,这些参数都是已经定义好了的, 我们选择性的使用就好了 ,一般我们使用 @SuppressWarnings(“all”)

二、元注解


除了 Java 中为我们定义好的注解,我们还可以自定义注解, Java定义了4个标准的元注解(meta-annotation)类型,他们被用来 提供对其他注解类型作说明 。
  

 @Retention(标明注解被保留的阶段)
        注解@Retention可以用来修饰注解,是注解的注解,称为元注解。
        Retention注解有一个属性value,是RetentionPolicy类型的,Enum RetentionPolicy是一个枚举类型,
        这个枚举决定了Retention注解应该如何去保持,也可理解为Rentention 搭配 RententionPolicy使用。RetentionPolicy有3个值:CLASS  RUNTIME   SOURCE
        按生命周期来划分可分为3类:
            @Retention:注解的保留位置         

    @Retention(RetentionPolicy.SOURCE)   //注解仅存在于源码中,在class字节码文件中不包含

    @Retention(RetentionPolicy.CLASS)     // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,

    @Retention(RetentionPolicy.RUNTIME)  // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
            这3个生命周期分别对应于:Java源文件(.java文件) ---> .class文件 ---> 内存中的字节码。
        那怎么来选择合适的注解生命周期呢?
            首先要明确生命周期长度 SOURCE < CLASS < RUNTIME ,所以前者能作用的地方后者一定也能作用。
            一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解,比如@Deprecated使用RUNTIME注解
            如果要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife),就用 CLASS注解;
            如果只是做一些检查性的操作,比如 @Override 和 @SuppressWarnings,使用SOURCE 注解。

        注解@Override用在方法上,当我们想重写一个方法时,在方法上加@Override,当我们方法的名字出错时,编译器就会报错
        注解@Deprecated,用来表示某个类或属性或方法已经过时,不想别人再用时,在属性和方法上用@Deprecated修饰
        注解@SuppressWarnings用来压制程序中出来的警告,比如在没有用泛型或是方法已经过时的时候
  

 @Target(标明注解使用的范围)
        Target说明的是Annotation所修饰的对象范围
      @Target:注解的作用目标        

    @Target(ElementType.TYPE)   //接口、类、枚举、注解

    @Target(ElementType.FIELD) //字段、枚举的常量

    @Target(ElementType.METHOD) //方法

    @Target(ElementType.PARAMETER) //方法参数

    @Target(ElementType.CONSTRUCTOR)  //构造函数

    @Target(ElementType.LOCAL_VARIABLE)//局部变量

    @Target(ElementType.ANNOTATION_TYPE)//注解

    @Target(ElementType.PACKAGE) ///包  

  

 @Inherited(标明注解可继承)
        @Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类
            当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。
            如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,
            直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。
  

 @Documented(标明是否生成javadoc文档)
        @Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员


三、自定义注解


    3.1自定义一个Log注解

package com.test.mybatisplus.aop;
import java.lang.annotation.*;

/**
 * @Description 日志注解
 * @project
 * @author:hf
 * @date:
 * @company:人生有限公司
 */
@Target({ElementType.PARAMETER,ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
    /**
     * 要执行的操作类型比如:add操作
     **/
    public String operationType() default "";

    /**
     * 要执行的具体操作比如:添加用户
     **/
    public String operationName() default "";

}

 3.2注解使用   

package com.test.mybatisplus.controller;

import com.test.mybatisplus.aop.Log;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**

@Api
@RestController
@RequestMapping("aopController")
@Slf4j
@Log(operationType="aopController",operationName="aopControllerT")
public class AopController {

    @Log(operationType="aaa",operationName="aaaT")
    public String aaa="ds";

    @GetMapping("/testAOP")
    @ApiOperation(value = "testAOP",notes = "testAOP")
    @Log(operationType="testAOP",operationName="测试接口")
    public String testAOP() {

       return "测试testAOP接口...";
    }


    public static void main(String[] args) throws Exception{
        //类
        AopController.class.getAnnotation(Log.class);
        AopController.class.getAnnotations();
        AopController.class.getDeclaredAnnotations();
        AopController.class.getAnnotationsByType(Log.class);
        AopController.class.getDeclaredAnnotation(Log.class);
        AopController.class.getDeclaredAnnotationsByType(Log.class);
        //方法
        AopController.class.getMethod("testAOP").getAnnotation(Log.class);
        AopController.class.getMethod("testAOP").getAnnotations();
        AopController.class.getMethod("testAOP").getDeclaredAnnotations();
        AopController.class.getMethod("testAOP").getAnnotationsByType(Log.class);
        AopController.class.getMethod("testAOP").getDeclaredAnnotation(Log.class);
        AopController.class.getMethod("testAOP").getDeclaredAnnotationsByType(Log.class);
        //变量
        AopController.class.getField("aaa").getAnnotation(Log.class);
        AopController.class.getField("aaa").getAnnotations();
        AopController.class.getField("aaa").getDeclaredAnnotations();
        AopController.class.getField("aaa").getAnnotationsByType(Log.class);
        AopController.class.getField("aaa").getDeclaredAnnotation(Log.class);
        AopController.class.getField("aaa").getDeclaredAnnotationsByType(Log.class);

    }
}

 3.3

 AopController.class.getAnnotation(Log.class);

3.4运行方法


 

AnnotationInvocationHandler 实现InvocationHandler,而InvocationHandler是实现动态代理必须的类(自行了解jdk动态代理)


 3.5查看源码,如何生成代理类   

通过Log logTest= AopController.class.getAnnotation(Log.class); 进入到class.java getAnnotation方法

    @SuppressWarnings("unchecked")
    public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
        Objects.requireNonNull(annotationClass);

        return (A) annotationData().annotations.get(annotationClass);
    }
	
	    private AnnotationData annotationData() {
        while (true) { // retry loop
            AnnotationData annotationData = this.annotationData;
            int classRedefinedCount = this.classRedefinedCount;
            if (annotationData != null &&
                annotationData.redefinedCount == classRedefinedCount) {
                return annotationData;
            }
            // null or stale annotationData -> optimistically create new instance
            AnnotationData newAnnotationData = createAnnotationData(classRedefinedCount);
            // try to install it
            if (Atomic.casAnnotationData(this, annotationData, newAnnotationData)) {
                // successfully installed new AnnotationData
                return newAnnotationData;
            }
        }
    }
	
	
	 private AnnotationData createAnnotationData(int classRedefinedCount) {
        Map<Class<? extends Annotation>, Annotation> declaredAnnotations =
            AnnotationParser.parseAnnotations(getRawAnnotations(), getConstantPool(), this);
        Class<?> superClass = getSuperclass();
        ......
        return new AnnotationData(annotations, declaredAnnotations, classRedefinedCount);
    }
	
	public static Map<Class<? extends Annotation>, Annotation> parseAnnotations(byte[] var0, ConstantPool var1, Class<?> var2) {
        if (var0 == null) {
            return Collections.emptyMap();
        } else {
            try {
                return parseAnnotations2(var0, var1, var2, (Class[])null);
            } catch (BufferUnderflowException var4) {
                throw new AnnotationFormatError("Unexpected end of annotations.");
            } catch (IllegalArgumentException var5) {
                throw new AnnotationFormatError(var5);
            }
        }
    }
	
	 private static Map<Class<? extends Annotation>, Annotation> parseAnnotations2(byte[] var0, ConstantPool var1, Class<?> var2, Class<? extends Annotation>[] var3) {
        LinkedHashMap var4 = new LinkedHashMap();
        ByteBuffer var5 = ByteBuffer.wrap(var0);
        int var6 = var5.getShort() & '\uffff';

        for(int var7 = 0; var7 < var6; ++var7) {
            Annotation var8 = parseAnnotation2(var5, var1, var2, false, var3);
            if (var8 != null) {
                Class var9 = var8.annotationType();
                if (AnnotationType.getInstance(var9).retention() == RetentionPolicy.RUNTIME && var4.put(var9, var8) != null) {
                    throw new AnnotationFormatError("Duplicate annotation for class: " + var9 + ": " + var8);
                }
            }
        }
		
		
		
		 private static Annotation parseAnnotation2(ByteBuffer var0, ConstantPool var1, Class<?> var2, boolean var3, Class<? extends Annotation>[] var4) {
			......
            return annotationForMap(var6, var10);
        }
    }
	
	   public static Annotation annotationForMap(final Class<? extends Annotation> var0, final Map<String, Object> var1) {
        return (Annotation)AccessController.doPrivileged(new PrivilegedAction<Annotation>() {
            public Annotation run() {
                return (Annotation)Proxy.newProxyInstance(var0.getClassLoader(), new Class[]{var0}, new AnnotationInvocationHandler(var0, var1));
            }
        });
    }
	

最后进入的annotationForMap 就是实现jdk动态代理的代码

 public static Annotation annotationForMap(final Class<? extends Annotation> var0, final Map<String, Object> var1) {
        return (Annotation)AccessController.doPrivileged(new PrivilegedAction<Annotation>() {
            public Annotation run() {
                return (Annotation)Proxy.newProxyInstance(var0.getClassLoader(), new Class[]{var0}, new AnnotationInvocationHandler(var0, var1));
            }
        });
    }

 

3.6下面六个方法执行到最后都会用到动态代理

 java的反射包中获取一个元素(Class、 Method、Constructor、Field)上的注解对象主要有6个方法获取的都是运行时注解。
        getAnnotation(Class<T> annotationClass)、
        getAnnotations()、
        getAnnotationsByType(Class<T> annotationClass)、
        getDeclaredAnnotation(Class<T> annotationClass)、
        getDeclaredAnnotations()、
        getDeclaredAnnotationsByType(Class<T> annotationClass)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值