Spring4-@Enable** 注解的实现原理
背景
在前面的工作中使用SpringBoot的时候,我碰到了很多的使用@Enable***注解的地方,使用上也都是加在@Configuration 类注解的类上面,比如:
(1)@EnableAutoConfiguration 开启自动扫描装配Bean
(2)@EnableScheduling 开启计划任务的支持
(3)@EnableTransactionManagement 开启注解式事务的支持。
(4)@EnableCaching开启注解式的缓存支持。
(5)@EnableAspectJAutoProxy 开启对AspectJ自动代理的支持,
还有一些我没用过,但是听过的,比如:
(6) @EnableAsync 开启异步方法的支持
(7) @EnableWebMvc 开启Web MVC的配置支持。
(8) @EnableConfigurationProperties 开启对@ConfigurationProperties注解配置Bean的支持。
(9)@EnableJpaRepositories 开启对Spring Data JPA Repository的支持。
通过简单的加上这些@Enable*注解就可以开启一些功能,避免了在XML时代, 需要自己手动的配置很多的XML代码,大大提升效率降低使用难度。 那么这种简单的操作带来的巨大的便利性是怎么实现的呢?
我研究了一下上面的这些自动开启某些功能的注解,发现了一些公共的特性,下面先举出一个例子:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(CachingConfigurationSelector.class)
public @interface EnableCaching {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
在这些所有的@Enable*注解的定义里面都包含一个 @Import 注解。 @Import注解在4.2之前只支持导入配置类,在4.2,@Import注解支持导入普通的java类,并将其声明成一个bean。这也说明了,自动开启的实现,其实是导入了一些配置类。
在上面各种@Enable**注解的实现中,导入配置类的形式,主要有三种类型:
1. 根据条件选择配置类(用的最多的)
以@EnableTransactionManagement 的定义为例:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
TransactionManagementConfigurationSelector通过条件选择需要导入的配置类, TransactionManagementConfigurationSelector最根接口是ImportSelector, 这个接口重写了selectImports方法,在此方法里面先进行判断。比如在此例中,若AdviceMode为PROXY(默认), 则返回AutoProxyRegistrar 和 ProxyTransactionManagementConfiguration 的配置类。
源码如下:
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}
2. 动态注册的Bean
以@EnableAspectJAutoProxy 为例:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口,ImportBeanDefinitionRegistrar的作用是在运行时自动添加Bean到已有的配置类,并在Spring容器启动时解析生成bean,通过重写方法:
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry)
来实现扫描注册逻辑。其中,AnnotationMetadata参数用来获得当前配置类上的注解,BeanDefinitionRegistry 参数用来注册Bean。源码如下:
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
3. 直接导入配置类
以@EnableScheduling 注解为例
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(SchedulingConfiguration.class)
@Documented
public @interface EnableScheduling {
}
从上面可以看到,直接导入了入配置类SchedulingConfiguration, 这个类注解了@Configuration,且注册了一个scheduledAnnotationProcessor的Bean,SchedulingConfiguration的源码如下:
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class SchedulingConfiguration {
@Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {
return new ScheduledAnnotationBeanPostProcessor();
}
}
总结: 其实上面的三种方法中,第一类是用的最多的。
Spring4-@Enable** 注解的实现原理的更多相关文章
- Spring高级特性之三:@Enable*注解的工作原理
Spring Boot中阐述热插拔技术的时候,简单地提及@Enable*注解.随着多种框架的应用及深入了解,@Enable*这个注解在各种框架中应用相当普及. 那么@Enable*注解工作原理是怎么样 ...
- Spring高级话题-@Enable***注解的工作原理
出自:http://blog.csdn.net/qq_26525215 @EnableAspectJAutoProxy @EnableAspectJAutoProxy注解 激活Aspect自动代理 & ...
- Spring的@Enable*注解的工作原理
转自:https://blog.csdn.net/chengqiuming/article/details/81586948 一 列举几个@Enable*注解的功能 @EnableAspectJAut ...
- springBoot @Enable*注解的工作原理
使用注解实现异步 RunnableDemo类 package com.boot.enable.bootenable; import org.springframework.scheduling.ann ...
- @Enable*注解的工作原理
@EnableAspectJAutoProxy @EnableAsync @EnableScheduling @EnableWebMv @EnableConfigurationProperties @ ...
- 自定义Spring-Boot @Enable注解
Spring-Boot中有很多Enable开头的注解,通过添加注解来开启一项功能,如 其原理是什么?如何开发自己的Enable注解? 1.原理 以@EnableScheduling为例,查看其源码,发 ...
- Spring Boot @Enable*注解源码解析及自定义@Enable*
Spring Boot 一个重要的特点就是自动配置,约定大于配置,几乎所有组件使用其本身约定好的默认配置就可以使用,大大减轻配置的麻烦.其实现自动配置一个方式就是使用@Enable*注解,见其名知 ...
- Spring Enable* 注解
Spring提供了一系列以Enable开头的注解,这些注解本质上是激活Spring的某些管理功能.比如,EnableWebMvc. 这个注解引入了MVC框架在Spring 应用中需要用到的所有bean ...
- Spring 3.1新特性之二:@Enable*注解的源码,spring源码分析之定时任务Scheduled注解
分析SpringBoot的自动化配置原理的时候,可以观察下这些@Enable*注解的源码,可以发现所有的注解都有一个@Import注解.@Import注解是用来导入配置类的,这也就是说这些自动开启的实 ...
- SpringBoot中神奇的@Enable*注解?
在SpringBoot开发过程,我们经常会遇到@Enable开始的好多注解,比如@EnableEurekaServer.@EnableAsync.@EnableScheduling等,今天我们就来分析 ...
随机推荐
- 学习go语言编程系列之定义变量
package main import ( "fmt" "math") func main() { // 1. 定义变量名age,不初始化,使用对应类型的默认值 ...
- ArcGIS出图调整
上周为了出一张高分辨率的结合表,大致学了一下出图的过程. (1)打开基础数据的图层属性栏,将某一项属性值显示出来,如下图设置: 注意,字体尽量设置得小一点,否则出图的时候,字太大,会很乱. (2)打开 ...
- 认证加密算法php hash_hmac和java hmacSha1的问题
public class Test{ public static void main(String[] args) throws Exception { String postString = &qu ...
- MySQL的一些基本命令笔记(2)
1.逻辑运算符的补充 between 的用法:(在....之间) select column1,column2,......columnN from 表名 where columnX between ...
- hashMap源码解析(五)
---恢复内容开始--- 首先抛出一个问题: 为什么hashMap一般使用String作为key? 这是我学习前辈们的博文时看到的一个问题,觉着很有意思,所以记录下来. 原因1: 我当时的第一反应是: ...
- SQL SERVER中一些常见性能问题的总结
1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免使用 left join 和 null 值判断.left join 比 in ...
- ms sql 导出单个表数据
然后都是下一步操作
- js apply使用
js中apply方法的使用 1.对象的继承,一般的做法是复制:Object.extend prototype.js的实现方式是: Object.extend = function(destinati ...
- react ,ant Design UI中table组件合并单元格并展开详情的问题
需求:购物车订单列表,如图: 一:单元格合并 遇到这种你会怎么办呢? 单元格合并? 还是其他的方法? 下面是我的处理方式,就是在table 组件的columns上处理,这里拿商品举例,其余的类似, ...
- 【tmos】使用joda-time来个格式化时间
代码 @Test public void test(){ DateTime dateTime = new DateTime(); String str = dateTime.toString(&quo ...