前言

在学习spring注解驱动开发之前,我们先来回顾一下Java的注解相关的知识。

一、注解的定义

直接看代码:

/*自定义注解@Book*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
public @interface Book {

    String name() default "";

    String author() ;
}

/*使用@Book注解标示该类*/
@Book(author = "Lucy")
public class BookSpring {

}

/*获取类上的注解,提取类上的注解有两种方式:1、asm字节码库 2、通过Class对象*/
public class AnnotationTest {

    @Test
    public void test1(){
        try {
            //方式一:通过Class对象,可以获取到类上的注解,因为Class实现了AnnotatedElement接口
            Class clazz = Class.forName("com.xinchao.test.annotation.BookSpring");
            Annotation[] annotations = clazz.getAnnotations();
            for (Annotation annotation: annotations) {
                System.out.println(annotation.getClass().getName());
                if(annotation instanceof Book){
                    Book book = (Book) annotation;
                    System.out.println(book.name()+book.author());
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    
}

java 注解获取方法入参 java如何通过注解获取类_元注解

上面简单的演示了一下自定义注解以及使用,再到提取类上的注解。接下来详细讲解如何自定义注解

1.自定义注解

第一步:首先使用 @interface标明该类是一个注解类
第二步:使用元注解修饰自定义的注解。元注解有 @Retention、@Documented、@Target、@Inherited、@Repeatable 5 种,下面我会详细介绍这五个修饰注解的注解的作用。
第三步:定义属性,String name() default “”; 在注解中定义属性时它的类型必须是 8 种基本数据类型外加 类、接口、注解及它们的数组。方法名代表属性的名称,只能是空参数。default是可选的默认值,如果不设置,那么使用的时候必须传。也就是没有default修饰,使用的时候不传会报错。

注意:如果属性名为value的时候,在使用时,如果只有value参数,那么vaue可以省略。示例:

@Table("student")
public class Student {
}
或者
@Table(value="student")
public class Student {
}

元注解:

@Retention

Retention 的英文意为保留期的意思。当 @Retention 应用到一个注解上的时候,它解释说明了这个注解的的存活时间。
它的取值如下:

  • RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
  • RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。
  • RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。
@Documented

顾名思义,这个元注解肯定是和文档有关。它的作用是能够将注解中的元素包含到 Javadoc 中去。

@Target

Target 是目标的意思,@Target 指定了注解运用的地方。
你可以这样理解,当一个注解被 @Target 注解时,这个注解就被限定了运用的场景。

类比到标签,原本标签是你想张贴到哪个地方就到哪个地方,但是因为 @Target 的存在,它张贴的地方就非常具体了,比如只能张贴到方法上、类上、方法参数上等等。@Target 有下面的取值

ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举
ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
ElementType.CONSTRUCTOR 可以给构造方法进行注解
ElementType.FIELD 可以给属性进行注解
ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
ElementType.METHOD 可以给方法进行注解
ElementType.PACKAGE 可以给一个包进行注解
ElementType.PARAMETER 可以给一个方法内的参数进行注解

@Inherited

Inherited 是继承的意思,但是它并不是说注解本身可以继承,而是说如果一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解。

注意:该注解只能继承类,如果是实现的接口则没有效果。

@Repeatable

Repeatable 自然是可重复的意思。@Repeatable 是 Java 1.8 才加进来的,所以算是一个新的特性。
什么样的注解会多次应用呢?通常是注解的值可以同时取多个。

2.注解的本质

「java.lang.annotation.Annotation」接口中有这么一句话,用来描述『注解』。

The common interface extended by all annotation types

所有的注解类型都继承自这个普通的接口(Annotation)

3.注解的提取

注解的提取主要有两种方式

  • 通过Class对象获取,因为Class实现了AnnotatedElement接口
  • ASM读取class字节码获取类的注解信息,Spring用的此种方式,优点就是不需要加载该类。
public interface AnnotatedElement {
	
    boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) //是否存在某个类型的注解
    
    <T extends Annotation> T getAnnotation(Class<T> annotationClass);//获取指定的注解
    
    Annotation[] getAnnotations();//获取所有的注解
    
    <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) 

    <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) ;

    <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass);
	
    Annotation[] getDeclaredAnnotations();//获取该类的注解不包含集成来的
}

二、Spring注解

基于Java的注解,Spring对注解功能进行了增强,其中包括组合注解,别名@AliasFor等,用于处理注解有一个工具类:AnnotatedElementUtils和AnnotationUtils。

举个例子,比如@Configuration注解:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {

	/*代表Configuration的value属性会被映射到Component注解的属性*/
    @AliasFor( annotation = Component.class)
    String value() default "";
}