写点什么

注解式开发!详细分析 Java 中各个注解的作用和使用方式

发布于: 2021 年 06 月 28 日
注解式开发!详细分析Java中各个注解的作用和使用方式

@Target

  • 作用: 指明了修饰的这个注解的使用范围, 即被描述的注解可以用在哪里


@Target(ElementType.Type)
复制代码


  • ElementType 取值的类型:

  • TYPE: 类,接口或者枚举

  • FIELD: 域,包含枚举常量

  • METHOD: 方法

  • PARAMETER: 参数

  • CONSTRUCTOR: 构造方法

  • LOCAL_VARIABLE: 局部变量

  • ANNOTATION_TYPE: 注解类型

  • PACKAGE:

@Retention

  • 作用: 指明修饰的注解的生存周期, 即会保留到哪个阶段

  • RetentionPolicy 的取值类型有三种:

  • SOURCE: 源码级别保留,编译后即丢弃

  • CLASS: 编译级别保留,编译后的 class 文件中存在,在 jvm 运行时丢弃,这是默认值

  • RUNTIME: 运行级别保留,编译后的 class 文件中存在,在 jvm 运行时保留,可以被反射调用

@Documented

  • 作用: 指明修饰的注解,可以被例如 javadoc 此类的工具文档化

  • 只负责标记

  • 没有成员取值

@Inherited

  • 作用: 允许子类继承父类中的注解

  • @Inherited 需要和 @AliasFor 一起使用: 在子注解对应的属性使用 @AliasFor

  • 注解是可以继承的,但是注解是不能继承父注解的属性

  • 也就是说,在类扫描时的注解的属性值依然是父注解的属性值,而不是自定义注解的属性值

  • 需要在注解的属性上使用 @AliasFor

@ComponentScan

  • 作用: 定义扫描的路径从中找出标识了需要装配的类自动装配到 spring 的 bean 容器中

  • 默认会扫描该类所在的包下所有的配置类

  • @ComponentScan 中的参数类型:

  • value: 用于对指定包的路径进行扫描

  • basePackages: 用于指定包的路径进行扫描,用法和 value 一样.建议使用 value

  • basePackageClasses: 用于对指定某个类的所在的包的路径进行扫描

  • nameGenerator: 用于为 Spring 容器中的检测到 bean 组件命名

  • useDefaultFilters: 是否开启对 @Component,@Repository,@Service,@Controller 的类进行检测

  • excludeFilters: 按照过滤条件进行排除

  • FilterType.ANNOTATION: 按照注解

  • FilterType.ASSIGNABLE_TYPE: 按照给定的类型

  • FilterType.ASPECTJ: 使用 ASPECTJ 表达式

  • FilterType.REGEX: 使用正则表达式

  • FilterType.CUSTOM: 按照自定义规则

  • includeFilters: 按照过滤条件进行包含

  • FilterType.ANNOTATION: 按照注解

  • FilterType.ASSIGNABLE_TYPE: 按照给定的类型

  • FilterType.ASPECTJ: 使用 ASPECTJ 表达式

  • FilterType.REGEX: 使用正则表达式

  • FilterType.CUSTOM: 按照自定义规则

@Filter

  • 作用: 配置过滤条件的过滤器注解

  • @Filter 中的参数类型:

  • type

  • class

@interface

  • 作用: 自定义注解

  • 自动继承 java.lang.annotation.Annotation 接口,由编译程序自动完成其他细节

  • 在定义注解时,不能继承其他的注解或接口

  • @interface 用来声明一个注解:

  • 其中的每一个方法实际上是声明一个配置参数

  • 方法的名称就是参数的名称

  • 方法的返回值类型就是参数的类型

  • 返回值类型只能是基本类型,Class,String,enum

  • 可以通过 default 来声明参数的默认值

  • 定义注解的格式:


public @interface 注解名 {定义体}
复制代码


  • 注解参数支持的数据类型:

  • 基本数据类型: int,float,boolean,byte,double,char,long,short

  • String 类型

  • Class 类型

  • enum 类型

  • Annotation 类型

  • 以上类型组合的数组

  • Annotation 类型中参数设定规则:

  • 只能用 public 或 default 默认访问权修饰:

  • 参数成员只能用基本类型 byte,short,char,int,long,float,double,boolean 八种基本数据类型和 String,Enum,Class,annotations 等数据类型,以及这一些类型的数组

  • 如果只有一个参数成员,最好把参数名称设为 value,后加小括号

  • 注解元素的默认值:

  • 注解元素必须有确定的值

  • 要么在定义注解的默认值中指定,要么在使用注解时指定,非基本类型的注解元素的值不可为 null

  • 因此使用空字符串或 0 作为默认值约束

  • 这个约束使得处理器很难表现一个元素的存在或缺失的状态:

  • 因为每个注解的声明中,所有元素都存在,并且都具有相应的值

  • 为了绕开这个约束,只能定义一些特殊的值(比如空字符串或者负数),表示某个元素不存在

@AliasFor

  • 作用: 为注解的属性添加别名

  • 在同一个注解内,对两个不同的属性一起使用,互为别名:

  • 无论为哪个属性名设置属性值,另一个属性名也是同样的属性值

  • 互为别名的属性值必须相同,否则会报错

  • 属性必须要有默认的属性值


public @interface RequestMapping {       @AliasFor("path")       // 此时path和value值必须是一样的,否则会报错    String[] value() default {};
@AliasFor("value") // 此时path和value值必须是一样的,否则会报错 String[] path() default {}; }
复制代码


  • 显式的覆盖元注解中的属性:

  • 显式的为元注解的属性设置别名

  • 属性类型,属性默认值必须相同

  • @AliasFor 只能为作为当前注解的元注解起别名

  • 示例:


@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = AopConfig.class)public class AopUtilsTest {}
复制代码


要想替换 @ContextConfiguration(classes = AopConfig.class) 注解,可以这样定义一个标签:


@Retention(RetentionPolicy.RUNTIME)@ContextConfigurationpublic @interface Context {    @AliasFor(value = "classes", annotation = ContextConfiguration.class)    Class<?>[] cs() default {};}
复制代码


  1. 因为 @ContextConfiguration 注解本身被定义为 @Inherited 的,所以 Context 注解即可理解为继承 @ContextConfiguration 注解

  2. cs 属性等同于 @ContextConfiguration 属性中的 classes 属性.使用了 @AliasFor 标签,分别设置:

  3. value: 作为哪个属性的别名

  4. annotation: 作为哪个注解的别名


使用 Context 标签的可以达到同样效果:


@RunWith(SpringJUnit4ClassRunner.class)@STC(cs = AopConfig.class)public class AopUtilsTest {}
复制代码


  • 在一个注解中隐式声明别名:


 @ContextConfiguration public @interface MyTestConfig {
@AliasFor(annotation = ContextConfiguration.class, attribute = "locations") String[] value() default {};
@AliasFor(annotation = ContextConfiguration.class, attribute = "locations") String[] groovyScripts() default {};
@AliasFor(annotation = ContextConfiguration.class, attribute = "locations") String[] xmlFiles() default {}; }
复制代码


这就是在统一注解中隐式声明别名:


  1. MyTestConfig 注解中 ,value,groovyScripts,xmlFiles 都定义为 @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")的别名

  2. 在这个注解中 ,value,groovyScripts 和 xmlFiles 也互为别名


  • 别名的传递:

  • @AliasFor 注解是允许别名之间的传递的:

  • 如果 A 是 B 的别名,并且 B 是 C 的别名,那么 A 是 C 的别名


@MyTestConfig public @interface GroovyOrXmlTestConfig {
@AliasFor(annotation = MyTestConfig.class, attribute = "groovyScripts") String[] groovy() default {};
@AliasFor(annotation = ContextConfiguration.class, attribute = "locations") String[] xml() default {}; }
复制代码


  1. GroovyOrXmlTestConfig @MyTestConfig 作为元注解

  2. 定义了 groovy 属性,并作为 MyTestConfig 中的 groovyScripts 属性的别名

  3. 定义了 xml 属性,并作为 ContextConfiguration 中的 locations 属性的别名

  4. 因为 MyTestConfig 中的 groovyScripts 属性本身就是 ContextConfiguration 中的 locations 属性的别名,所以 xml 属性和 groovy 属性也互为别名


  • @Alias 中的属性:

  • annotation: 类类型,别名属性的类的类型,即别名的属性属于哪个注解类

  • attribute: 需要别名的属性

  • value: 属性的别名

@Import

  • @Import 支持导入普通的 Java 类,并声明为一个 Bean

  • @Import 使用场景:

  • @Import 主要用在基于 Java 代码显式创建 bean 的过程中

  • @Import 用于将多个分散的 Java Config 配置类融合成一个完整的 config 类

  • 配置类的组合主要发生在跨模块或者跨包的配置类引用过程中: 将多个按功能或者按业务划分的配置文件导入到单个配置文件中,避免将所有配置写在一个配置中

  • @Import 与 @ImportResource 注解的作用类似

  • 使用 @ImportResource 和 @Value 可以进行资源文件的读取

SpringBoot

@SpringBootApplication

  • 包含:

  • @Configuration

  • @EnableAutoConfiguration

  • @ComponentScan

  • 通常用在主类上

@ConfigurationProperties

  • 可以使用 @ConfigurationProperties 获取大量配置在 application.properties application.yml 中参数的参数值

  • @ConfigurationProperties 的使用: 要为每个捕获的外部属性提供一个带有字段的类

  • 前缀 prefix 定义的相关的外部属性要绑定到类的字段上

  • 根据 SpringBoot 宽松的绑定规则,类属性的名称必须与外部属性名称匹配

  • 可以将类类型的 bean 使用 @Bean 注解的方法注入到另一个 bean 中,那么这个 bean 可以以类型安全的方式访问外部配置的参数值

  • 可以简单地用一个值初始化一个字段来定义一个默认值. 最好与配置文件中的值相同

  • 类本身可以是包私有的

  • 类的字段必须有公共 setter 方法

  • 激活 @ConfigurationProperties:

  • 通过添加 @Component 注解让 ComponentScan 扫描到

  • 只有当该类所在的包被 Spring 的 @ComponentScan 扫描到才会生效.默认情况下,该注解会扫描在主应用类下所有包结构


  @Component  @ConfigurationProperties(prefix = "spring.logger")  class LogProperties {    ...  }
复制代码


  • 通过 Spring Java Configuration 特性激活 @ConfigurationProperties

  • 只要 MailModuleConfiguration 类被 SpringBoot 应用扫描到,就可以在应用上下文中访问 MailModuleProperties bean


  @Configuration  class PropertiesConfig {    @Bean     public LogModuleProperties logModuleProperties() {      return new logModuleProperties();    }  }
复制代码


  • 同时可以使用 @EnableConfigurationProperties 注解使得 SpringBoot 找到这个类. 这个注解用了 @Import(EnableConfigurationPropertiesImportSelector.class) 实现


 @Configuration @EnableConfigurationProperties(LogModuleProperties.class) class PropertiesConfig { }
复制代码


激活一个 @ConfigurationProperties 类时最好模块化应用程序,并让每个模块提供自己的 @ConfigurationProperties 类,只提供模块需要的属性.这样可以使得在不影响其他模块的情况下重构一个模块中的属性变得更加方便.因此不建议在程序类本身上使用 @EnableConfigurationProperties, 应该在特定模块的 @Configuration 类上使用 @EnableConfigurationProperties, 该类也可以利用包私有的可见性对特定应用程序其余部分隐藏属性


  • @ConfigurationProerties 中无法转换的属性:

  • 当为 @ConfigurationProperties 中的属性配置错误的值时,又不希望 SpringBoot 应用启动失败.可以设置 ignoreInvalidFields 注解属性为 true, 默认为 false


@ConfigurationProperties(prefix = "spring.logger", ignoreInvalidFields = true)public class LogModuleProperties {  private Boolean enabled = Boolean.True;}
复制代码


SpringBoot 将会设置 enable 字段为设定好的默认值. 如果没有设定默认值 ,enabled 的值将为 null, 因为这里定义的是 boolean 的包装类 Boolean


  • @ConfigurationProperties 中未知的属性:

  • 默认情况下,SpringBoot 会忽略不能绑定到 @ConfigurationProperties 类字段的属性

  • 当配置文件中又一个属性实际没有绑定到 @ConfigurationProperties 类时,希望 SpringBoot 启动失败

  • 或者是以前使用过这个属性,但已经被删除了,希望被触发告知手动从 application.properties 删除这个属性

  • 这是需要设置 ignoreUnknownFields 注解属性为 false, 默认为 true


@ConfigurationProperties(prefix = "spring.logger", ignoreUnknownFields = false)class LogModuleProperties {  private Boolean enabled = Boolean.TRUE;  private String defaultSubject;}
复制代码


对于 ignoreUnkownFields, 在 SpringBoot 中可能有两个带有 @ConfigurationProperties 的类,同时绑定到了同一个命名空间 (namespace) 上,其中一个类可能知道某个属性,另一个类却不知道某个属性,这样会导致启动失败.所以这个属性不再使用


  • 启动时校验 @ConfigurationProperties:

  • 如果希望配置参数在传入到应用中是有效的,可以通过在字段上添加 bean validation 注解,同时在类上添加 @Validated 注解


@ConfigurationProperties(prefix = "spring.logger")@Validated@Dataclass LogModuleProperties {  @NotNull private Boolean enabled;  @NotEmty private String defaultSubject;} 
复制代码


如果这些默认的验证注解不能满足验证要求的,可以自定义注解. 如果验证逻辑很特殊,可以实现一个方法,并用 @PostConstruct 标记,如果验证失败,方法抛出异常即可


  • 复杂属性类型:

  • 多数情况下,传递给应用的参数是基本字符串或者数字,有时又需要传递比如 List 的数据类型

  • List 和 Set:

  • 有两种方式让 SpringBoot 自动填充 List 属性:

  • application.properties 文件中以数组形式书写


      spring.logger.smtpServers[0]=server1      spring.logger.smtpServers[1]=server1
复制代码


  - **application.yml**本身支持**List**类型,可以在application.yml文件中添加
复制代码


      spring:        mail:          smtpServers:            - server1            - server2
复制代码


- **set**集合也是使用同样的配置方式
复制代码


  • 推荐使用 YML 做数据配置,能够更好的阅读,层次分明

  • Duration:

  • SpringBoot 内置支持从配置参数中解析 duration(持续时间):


  @Data  @ConfigurationProperties(prefix = "spring.logger")  class loggerModuleProperties {    private Duration pauseBetweenLogs;  }
复制代码


  • 既可以配置毫秒数值,也可以配置带有单位的文本:


  spring.logger.pause-between-logs=5s
复制代码


  • 如果配置 duration 没有写单位,默认按照毫秒来指定,也可以通过 @DurationUnit 来指定单位:


  @Data  @ConfigurationProperties(prefix = "spring.logger")  class loggerModuleProperties {    @DurationUnit(ChronoUnit.SECONDS)    private Duration pauseBetweenLogs;  }
复制代码


  • 常用单位如下:

  • ns: NANOSECONDS - 纳秒

  • us: MICROSECONDS - 微秒

  • ms: MILLISECONDS - 毫秒

  • s: SECONDS - 秒

  • m: MINUTES - 分

  • h: HOURS - 时

  • d: DAYS - 天

  • DataSize:

  • 与 Duration 用法一样,默认单位是 byte(字节) , 可以通过 @DataSizeUnit 单位指定


  @Data  @ConfigurationProperties(prefix = "spring.logger")  class loggerMailModuleProperties {    @DataSizeUnit(DataUnit.MEGABYTES)    private DataSize maxAttachmentSize = DataSize.ofMegebytes(2);  } 
复制代码


  • 添加配置:


  spring.logger.max-attachment-size=1MB
复制代码


输出的结果都是以 B(bytes) 为单位显示的


  • 常见单位如下:

  • B: BYTES

  • KB: KILOBYTES

  • MB: MEGEBYTES

  • GB: GIGABYTES

  • TB: TERABYTES

  • 自定义类型:

  • 有时候,想解析配置参数到自定义的对象类型上,比如自定义物品重量:


  spring.logger.max-attachment-weight=5kg
复制代码


  • MailModuleProeprties 中添加 Weight 属性:


  @Data  @ConfigurationProperties(prefix = "spring.logger")  class MailModuleProperties {    private Weight maxAttachmentWeight;  }
复制代码


  • 创建自定义转换器 converter:


  class WeightConverter implements Convert<String, Object> {    @Override    public Weight convert(String source) {      // 根据String类型的source创建并返回一个Weight类型的对象    }  }
复制代码


  • 将自定义转换器 converter 注册到 SpringBoot 上下文中


  @Configuration  class PropertiesConfig {    @Bean    @ConfigurationPropertiesBinding    public WeightConverter weightConverter() {      return new WeightConverter();    }  }
复制代码


@ConfigurationPropertiesBinding 注解是让 SpringBoot 使用该转换器做数据绑定


  • 标记配置属性为 Deprecated:


@DeprecatedConfigurationProperty(reason = "change name", replacement = "none")public String getDefaultSubject() {  return defaultSubject;}
复制代码


可以通过添加 @DeprecatedConfigurationProperty 注解到字段的 getter 方法上,来标示该字段为 deprecated


  • SpringBoot @ConfigurationProperties 注解在绑定类型安全的 Java Bean 时是非常强大的

  • 可以配合其注解属性和 @DeprecatedConfigurationProperty 注解让配置更加模块化

  • 如果使用 SpEL 表达式,只能选择 @Value 注解

@Repository

  • 用于标注数据访问组件,即 DAO 组件

@Service

  • 用于标注业务层组件

@RestController

  • 用于标注控制层组件

  • 包含:

  • @Controller

  • @ResponseBody

@Controller

  • 用于标注控制层组件

  • 需要返回页面时要使用 @Controller 而不是 @RestController

@ControllerAdvice

  • 用于定义 @ExceptionHandler, @InitBinder, @ModelAttribute, 并且应用到所有 @RequestMapping

  • @InitBinder: 在执行之前初始化数据绑定器

  • @ModelAttribute: 把值绑定到 Model 中,可以获取到该值

  • @ExceptionHandler: 全局异常捕捉处理

@Component

  • 泛指组件

  • 当组件无法归类时,可以使用这个注解进行标注

@ResponseBody

  • 表示该方法的返回结果直接被写入 http response body

  • 一般在异步获取数据时使用

  • 在使用 @RequestMapping 后,返回值通常解析为跳转路径

  • 比如:

  • 加上 @ResponseBody 后返回结果不会被解析为跳转路径,而是直接写入 HTTP Response Body

  • 异步获取 json 数据,加上 @ResponseBody 后,会直接返回 json 数据

@RequestBody

  • 参数前加上这个注解,表示该参数必填

  • 表示接收 json 字符串转为对象 List

@ComponentScan

  • 组件扫描

  • 扫描到有 @Component, @Cotroller, @Service 等这些注解的类,就会把这些类注册为 bean*

@Configuration

  • 表示该类是 Bean 的信息源

  • 相当于 XML 中的,一般标注在主类上

@ConditionOnProperty

  • 控制 Configuration 在条件成立时生效

  • 属性:

  • value: 数组,获取对应 property 的名称,与 name 不可以同时使用

  • prefix: property 名称的前缀,可有可无

  • name: 数组 ,property 完整名称或者部分名称(与 prefix 组合使用,组成完整的 property 名称),不可以与 value 同时使用

  • havingValue: 可与 name 组合使用,比较获取到的属性值与 havingValue 给定的值是否相同,相同才加载配置

  • matchMissing: 缺少该 property 时是否可以加载. 如果为 true, 没有该 property 也会正常加载. 如果为 false, 则没有该 property 时则会报错,默认为 false

  • relaxedNames: 是否支持松散匹配

@Bean

  • 相当于 XML 中的,标注在方法上

  • 表示生成一个 bean, 并交给 Spring 管理

@EnableAutoConfiguration

  • 使 SpringBoot 根据应用所声明的依赖来对 Spring 框架进行配置

  • 一般加在主类上

@Autowired

  • byType 方式

  • 使用已经配置好的 Bean, 完成属性,方法的组装

  • 可以对类成员,方法以及构造函数进行标注,完成自动装配的工作

  • 如果加上 @Autowired(required = false), 当找不到 bean 时也不会报错

@Qualifier

  • 当有多个同一类型的 Bean 时,可以使用 @Qualifier("name") 来指定

  • 需要和 @Autowired 一起使用

@Resource

  • @Resource(name = "name", type = "type")

  • 如果没有属性的话,默认为 byName,@Autowired 功能类似

@RequestMapping

  • @RequestMapping 是一个用来处理请求地址映射的注解,可以使用在类或者方法上

  • 用在类上时,表示类中所有响应请求的方法都以该地址作为父路径

  • @RequestMapping 有六个属性:

  • params: 指定 request 中必须包含某些参数值,才让该方法处理请求

  • headers: 指定 request 中必须包含某些指定的 header 值,才能让该方法处理请求

  • value: 指定请求的实际地址. 指定的地址可以是 URI Template 模式

  • method: 指定请求的 method 类型 ,GET, POST, PUT,DELETE

  • consumes: 指定处理请求的提交内容类型 - Content-Type. 比如: application,json,text,html

  • produces: 指定返回的内容类型,仅当 request 请求头中的 (Accept) 类型中包含该指定类型才返回

@GetMapping

  • @GetMapping, @PostMapping 是组合注解

  • 相当于 @RequestMapping(value = "/", method = RequestMethod.Get(Post, Put, Delete))

@RequestParam

  • 用在方法的参数前面

  • 相当于 request.getParameter

@PathVariable

  • 路径变量: RequestMapping("user/get/mac/{macAddress}")


public String getByMacAddress(@PathVariable("macAddress") String macAddress) {}
复制代码


参数与大括号里的名字相同的话,注解后括号里的内容可以不填

全局异常处理

@ControllerAdvice

  • 包含 @Component

  • 可以被扫描到

  • 统一异常处理

@ExceptionHandler

  • @Exceptionhandler(Exception.class)

  • 用在方法上面,表示遇到这个异常就执行这个方法

SpringCloud

@EnableEurekaServer

  • 用在 SpringBoot 启动类上

  • 表示这是一个 Eureka 服务注册中心

@EnableDiscoveryClient

  • 用在 SpringBoot 启动类上

  • 表示这是一个服务,可以被注册中心找到

@LoadBalanced

  • 开启负载均衡能力

@EnableCircuitBreaker

  • 用在 SpringBoot 启动类上

  • 开启断路器功能

HystrixCommand

  • @HystrixCommand(fallbackMethod = "backMethod")

  • 用在方法上,表示 fallbackMethod 指定断路回调方法

@EnableConfigServer

  • 用在 SpringBoot 启动类上

  • 表示这是一个配置中心,开启 Config Server

@EnableZuulProxy

  • 用在 SpringBoot 启动类上

  • 表示开启 zuul 路由

@SpringCloudApplication

  • 微服务注解集合,包含:

  • @SpringBootApplication: SpringBoot 注解

  • @EnableDiscoveryClient: 注册服务中心 Eureka 注解

  • @EnableCircuitBreaker: 断路器注解

  • 这是每一个微服务必须应该有的注解

发布于: 2021 年 06 月 28 日阅读数: 6
用户头像

一位攻城狮的自我修养 2021.04.06 加入

分享技术干货,面试题和攻城狮故事。 你的关注支持是我持续进步的最大动力! https://github.com/ChovaVea

评论

发布
暂无评论
注解式开发!详细分析Java中各个注解的作用和使用方式