注解式开发!详细分析 Java 中各个注解的作用和使用方式
@Target
作用: 指明了修饰的这个注解的使用范围, 即被描述的注解可以用在哪里
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 来声明参数的默认值
定义注解的格式:
注解参数支持的数据类型:
基本数据类型: 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
作用: 为注解的属性添加别名
在同一个注解内,对两个不同的属性一起使用,互为别名:
无论为哪个属性名设置属性值,另一个属性名也是同样的属性值
互为别名的属性值必须相同,否则会报错
属性必须要有默认的属性值
显式的覆盖元注解中的属性:
显式的为元注解的属性设置别名
属性类型,属性默认值必须相同
@AliasFor 只能为作为当前注解的元注解起别名
示例:
要想替换 @ContextConfiguration(classes = AopConfig.class) 注解,可以这样定义一个标签:
因为 @ContextConfiguration 注解本身被定义为 @Inherited 的,所以 Context 注解即可理解为继承 @ContextConfiguration 注解
cs 属性等同于 @ContextConfiguration 属性中的 classes 属性.使用了 @AliasFor 标签,分别设置:
value: 作为哪个属性的别名
annotation: 作为哪个注解的别名
使用 Context 标签的可以达到同样效果:
在一个注解中隐式声明别名:
这就是在统一注解中隐式声明别名:
在 MyTestConfig 注解中 ,value,groovyScripts,xmlFiles 都定义为 @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")的别名
在这个注解中 ,value,groovyScripts 和 xmlFiles 也互为别名
别名的传递:
@AliasFor 注解是允许别名之间的传递的:
如果 A 是 B 的别名,并且 B 是 C 的别名,那么 A 是 C 的别名
GroovyOrXmlTestConfig 把 @MyTestConfig 作为元注解
定义了 groovy 属性,并作为 MyTestConfig 中的 groovyScripts 属性的别名
定义了 xml 属性,并作为 ContextConfiguration 中的 locations 属性的别名
因为 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 扫描到才会生效.默认情况下,该注解会扫描在主应用类下所有包结构
通过 Spring 的 Java Configuration 特性激活 @ConfigurationProperties
只要 MailModuleConfiguration 类被 SpringBoot 应用扫描到,就可以在应用上下文中访问 MailModuleProperties bean
同时可以使用 @EnableConfigurationProperties 注解使得 SpringBoot 找到这个类. 这个注解用了 @Import(EnableConfigurationPropertiesImportSelector.class) 实现
激活一个 @ConfigurationProperties 类时最好模块化应用程序,并让每个模块提供自己的 @ConfigurationProperties 类,只提供模块需要的属性.这样可以使得在不影响其他模块的情况下重构一个模块中的属性变得更加方便.因此不建议在程序类本身上使用 @EnableConfigurationProperties, 应该在特定模块的 @Configuration 类上使用 @EnableConfigurationProperties, 该类也可以利用包私有的可见性对特定应用程序其余部分隐藏属性
@ConfigurationProerties 中无法转换的属性:
当为 @ConfigurationProperties 中的属性配置错误的值时,又不希望 SpringBoot 应用启动失败.可以设置 ignoreInvalidFields 注解属性为 true, 默认为 false
SpringBoot 将会设置 enable 字段为设定好的默认值. 如果没有设定默认值 ,enabled 的值将为 null, 因为这里定义的是 boolean 的包装类 Boolean
@ConfigurationProperties 中未知的属性:
默认情况下,SpringBoot 会忽略不能绑定到 @ConfigurationProperties 类字段的属性
当配置文件中又一个属性实际没有绑定到 @ConfigurationProperties 类时,希望 SpringBoot 启动失败
或者是以前使用过这个属性,但已经被删除了,希望被触发告知手动从 application.properties 删除这个属性
这是需要设置 ignoreUnknownFields 注解属性为 false, 默认为 true
对于 ignoreUnkownFields, 在 SpringBoot 中可能有两个带有 @ConfigurationProperties 的类,同时绑定到了同一个命名空间 (namespace) 上,其中一个类可能知道某个属性,另一个类却不知道某个属性,这样会导致启动失败.所以这个属性不再使用
启动时校验 @ConfigurationProperties:
如果希望配置参数在传入到应用中是有效的,可以通过在字段上添加 bean validation 注解,同时在类上添加 @Validated 注解
如果这些默认的验证注解不能满足验证要求的,可以自定义注解. 如果验证逻辑很特殊,可以实现一个方法,并用 @PostConstruct 标记,如果验证失败,方法抛出异常即可
复杂属性类型:
多数情况下,传递给应用的参数是基本字符串或者数字,有时又需要传递比如 List 的数据类型
List 和 Set:
有两种方式让 SpringBoot 自动填充 List 属性:
在 application.properties 文件中以数组形式书写
推荐使用 YML 做数据配置,能够更好的阅读,层次分明
Duration:
SpringBoot 内置支持从配置参数中解析 duration(持续时间):
既可以配置毫秒数值,也可以配置带有单位的文本:
如果配置 duration 没有写单位,默认按照毫秒来指定,也可以通过 @DurationUnit 来指定单位:
常用单位如下:
ns: NANOSECONDS - 纳秒
us: MICROSECONDS - 微秒
ms: MILLISECONDS - 毫秒
s: SECONDS - 秒
m: MINUTES - 分
h: HOURS - 时
d: DAYS - 天
DataSize:
与 Duration 用法一样,默认单位是 byte(字节) , 可以通过 @DataSizeUnit 单位指定
添加配置:
输出的结果都是以 B(bytes) 为单位显示的
常见单位如下:
B: BYTES
KB: KILOBYTES
MB: MEGEBYTES
GB: GIGABYTES
TB: TERABYTES
自定义类型:
有时候,想解析配置参数到自定义的对象类型上,比如自定义物品重量:
在 MailModuleProeprties 中添加 Weight 属性:
创建自定义转换器 converter:
将自定义转换器 converter 注册到 SpringBoot 上下文中
@ConfigurationPropertiesBinding 注解是让 SpringBoot 使用该转换器做数据绑定
标记配置属性为 Deprecated:
可以通过添加 @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}")
参数与大括号里的名字相同的话,注解后括号里的内容可以不填
全局异常处理
@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: 断路器注解
这是每一个微服务必须应该有的注解
版权声明: 本文为 InfoQ 作者【攻城狮Chova】的原创文章。
原文链接:【http://xie.infoq.cn/article/70590ad977efbe7ee466a5847】。文章转载请联系作者。
评论