Spring Boot @ConditionalOnClass上的注解你了解多少-java元注解和注解 - 第404篇
  TEZNKK3IfmPf 2024年03月29日 35 0

缘起

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

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

一、元注解

1.1 元注解的源码结构

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

       从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

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

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

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

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

2.2 @RequestParam

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

(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;
}

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

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

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

2.3 @Bean

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

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

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

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

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

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

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

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

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

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

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

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

       我们发现元注解@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:

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

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

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

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

三、元注解class文件

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

       我们定义注解了:

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

       使用javap反编译一下:

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

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2024年03月29日 0

暂无评论

推荐阅读
TEZNKK3IfmPf