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等,今天我们就来分析 ...
随机推荐
- 利用 yEd 软件做元数据管理
利用 yEd 软件做元数据管理 yEd Diagram editor 是我常用的 flow chart 制图工具, 另外我也用它画 ER 和 use case 图. 总结一下我喜欢 yEd 的原因:1 ...
- CorelDrawX8安装时提示已安装另一个版本
(1)首先卸载VIsualC++ 2015 运行库. (2)如果有VisualC++ 2017运行库,卸载VisualC++2017运行库,即可.
- daemon_init函数:调用该函数把普通进程转变为守护进程
#include <unistd.h> #include <syslog.h> #include <fcntl.h> #include <signal.h&g ...
- Linux下运行jmeter
• 我们在做测试的时候,有时候要运行很久,公司用的测试服务器一般都是linux,就可以运行在linux下面,linux下面不能像windows一样有图形化界面,那怎么运行脚本呢,就先在windows上 ...
- Windows IIS 使用批处理脚本自动安装与卸载
IIS6:适用于win server 2003 :: ******************* :: * 安装 :: ******************* :Install Cls @echo. &a ...
- java基础 包装类
包装类在集合中用来定义集合元素的类型. 1.Integer.MIN_VALUE:int类型的最小值:-2^31 2.Integer.MAX_VALUE:int类型的最大值:2^31-1 3.int ...
- react-踩坑记录——页面底部多出一倍高度的空白
挂载slider组件后页面底部多出一倍高度的空白,如下: slider组件内容⬇️: class Slider extends Component{ constructor(){ super(); } ...
- 1Mybatis入门--1.1单独使用jdbc编程问题总结
1.1.1 jdbc程序 Public static void main(String[] args) { Connection connection = null; PreparedStatemen ...
- 配置中文分词器 IK-Analyzer-Solr7
先下载solr7版本的ik分词器,下载地址:http://search.maven.org/#search%7Cga%7C1%7Ccom.github.magese分词器GitHub源码地址:http ...
- 贝叶斯优化(Bayesian Optimization)深入理解
目前在研究Automated Machine Learning,其中有一个子领域是实现网络超参数自动化搜索,而常见的搜索方法有Grid Search.Random Search以及贝叶斯优化搜索.前两 ...