Spring Boot @ConditionalOnClass上的注解你了解多少-java元注解和注解 - 第404篇

缘起

       在前面的文章中,我们使用了注解@ConditionalOnClass,在此注解上面有其它的注解,在自定义注解的时候,如果不明白上面的这些配置,那可能就会搞错这个注解的使用。

一、元注解

1.1 元注解的源码结构

       从java.lang.annotation包截图看,一共定义了6个注解:

(1)@Document

(2)@Target

(3)@Retention

(4)@Inherited

(5)@Native

(6)@Repeatable

       其中前4个是元注解

1.2 元注解的定义

       所谓元注解就是注解的注解,元注解负责注解自定义注解,你可以看到许多自定义的注解上面都有这些元注解:

       例如Spring Boot的注解@ConditionalOnClass:

@Target({ ElementType.TYPE, ElementType.METHOD })@Retention(RetentionPolicy.RUNTIME)@Documented@Conditional(OnClassCondition.class)public @interface ConditionalOnClass {     Class<?>[] value() default {};     String[] name() default {};}

1.3 元注解的用途

1.3.1 @Target:注解的使用范围

       标识注解的使用范围,可以赋值为ElementType类型,ElementType定义如下:

public enum ElementType {    /** Class, interface (including annotation type), or enum declaration : 接口、类、枚举、注解 */    TYPE,    /** Field declaration (includes enum constants): 字段、枚举的常量 */    FIELD,    /** Method declaration: 方法 */    METHOD,    /** Formal parameter declaration:方法参数 */    PARAMETER,    /** Constructor declaration:构造函数 */    CONSTRUCTOR,    /** Local variable declaration:局部变量 */    LOCAL_VARIABLE,    /** Annotation type declaration:注解 */    ANNOTATION_TYPE,    /** Package declaration:包 */    PACKAGE,    /**     * Type parameter declaration:类型参数上     *     * @since 1.8     */    TYPE_PARAMETER,    /**     * Use of a type     *     * @since 1.8     */    TYPE_USE}

1.3.2 @Documented:是否要被写入javadoc

@Document注解用途主要是标识类型是否要被收入javadoc

1.3.3 @Inherited:是否可以被子类继承

       说明子类可以继承父类中的该注解

1.3.4 @Retention:注解保留的位置

       注解的保留位置,可以赋值 RetentionPolicy类型,RetentionPolicy定义如下:

public enum RetentionPolicy {    /**     * Annotations are to be discarded by the compiler.     */    SOURCE,    /**     * Annotations are to be recorded in the class file by the compiler     * but need not be retained by the VM at run time.  This is the default     * behavior.     */    CLASS,    /**     * Annotations are to be recorded in the class file by the compiler and     * retained by the VM at run time, so they may be read reflectively.     *     * @see java.lang.reflect.AnnotatedElement     */    RUNTIME}

(1)RetentionPolicy.SOURCE:表明注解会被编译器丢弃,字节码中不会带有注解信息

(2)RetentionPolicy.CLASS:表明注解会被写入字节码文件,且是@Retention的默认值

(3)RetentionPolicy.RUNTIME:表明注解会被写入字节码文件,并且能够被JVM 在运行时获取到,可以通过反射的方式解析到

二、举例说明

2.1 @ConditionalOnClass

(1)@Target:说明该注解可以使用在TYPE(接口、类、枚举、注解)和METHOD(方法)上。

(2)@Retention(RetentionPolicy.RUNTIME):表明注解会被写入字节码文件,并且能够被JVM 在运行时获取到,可以通过反射的方式解析到。

(3)Documented:要写入到javadoc中。



2.2 @RequestParam

(1)@Target(ElementType.PARAMETER):只能在参数上进行使用。

(2)@Retention(RetentionPolicy.RUNTIME):表明注解会被写入字节码文件,并且能够被JVM 在运行时获取到,可以通过反射的方式解析到。

(3)Documented:要写入到javadoc中。

       RequestParam可以看下具体的例子:

/** * 接收普通请求参数 * http://localhost:8080/test16?name=wuqian * url参数中的name必须要和@RequestParam("name")一致 * @return */@RequestMapping("test16")public ModelAndView test16(@RequestParam("name")String name){    ModelAndView mv = new ModelAndView();    mv.setViewName("hello2");    mv.addObject("msg", "接收普通的请求参数:" + name);    return mv;}

       如果将此注解参数强制使用在方法上就会编译错误:

       错误信息:'@RequestParam' not applicable to method.(“@RequestParam”不适用于方法。)

2.3 @Bean

(1)@Target:说明该注解可以使用在METHOD(方法)和ANNOTATION_TYPE(注解类型)上。

(2)@Retention(RetentionPolicy.RUNTIME):表明注解会被写入字节码文件,并且能够被JVM 在运行时获取到,可以通过反射的方式解析到。

(3)Documented:要写入到javadoc中。

       对于@Target可以在方法上使用,想必大家这个没有什么疑惑,对于ANNOTATION_TYPE(注解类型)的话,这个就是注解类型,什么意思呢?

       就是这个注解使用被其它注解进行组合注解,也就是说可以将@Bean这个注解用在自定义注解的上面。

       这里举个栗子,定义了两个注解MyAnno和MyAnno1:

       对于@MyAnno配置了@Target({ElementType.ANNOTATION_TYPE}),所以可以讲此注解定义在MyAnno1上。

       当删除@MyAnno 的配置ElementType.ANNOTATION_TYPE的时候,那么就会报错:

       我们发现元注解@Document、@Target、@Retention、@Inherited上都配置了@Target(ElementType.ANNOTATION_TYPE)。

       所以对于配置了@Target(ElementType.ANNOTATION_TYPE)还有一种解释:

由@Target(ElementType.ANNOTATION_TYPE)注释的每个注释称为Meta-annotation。这意味着,您可以定义自己的自定义注释,这些注释是许多注释的合并,组合成一个注释以创建composed annotations。

       特别说明:@Target(ElementType.TYPE)也是可以使用在注解上的。

2.4 @Data

       Lombok的注解@Data:

(1)@Target:说明该注解可以使用在TYPE(接口、类、枚举、注解)上。

(2)@Retention(RetentionPolicy.SOURCE):表明注解会被编译器丢弃,字节码中不会带有注解信息。

       所以@Data注解的类在被编译之后,此类上面并不会保留@Data的注解。因此通过反射技术无法获取到@Data这个注解。

三、元注解class文件

       我们通过反编译可以看出来最终是一个接口:

       我们定义注解了:

       使用javap反编译一下:


购买完整视频,请前往:http://www.mark-to-win.com/TeacherV2.html?id=287