背景

在前面的工作中使用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代码,大大提升效率降低使用难度。 那么这种简单的操作带来的巨大的便利性是怎么实现的呢?

我研究了一下上面的这些自动开启某些功能的注解,发现了一些公共的特性,下面先举出一个例子:

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Import(CachingConfigurationSelector.class)
  5. public @interface EnableCaching {
  6. boolean proxyTargetClass() default false;
  7. AdviceMode mode() default AdviceMode.PROXY;
  8. int order() default Ordered.LOWEST_PRECEDENCE;
  9. }

在这些所有的@Enable*注解的定义里面都包含一个 @Import 注解。 @Import注解在4.2之前只支持导入配置类,在4.2,@Import注解支持导入普通的java类,并将其声明成一个bean。这也说明了,自动开启的实现,其实是导入了一些配置类。

在上面各种@Enable**注解的实现中,导入配置类的形式,主要有三种类型:

1. 根据条件选择配置类(用的最多的)

以@EnableTransactionManagement 的定义为例:

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Import(TransactionManagementConfigurationSelector.class)
  5. public @interface EnableTransactionManagement {
  6. boolean proxyTargetClass() default false;
  7. AdviceMode mode() default AdviceMode.PROXY;
  8. int order() default Ordered.LOWEST_PRECEDENCE;
  9. }

TransactionManagementConfigurationSelector通过条件选择需要导入的配置类, TransactionManagementConfigurationSelector最根接口是ImportSelector, 这个接口重写了selectImports方法,在此方法里面先进行判断。比如在此例中,若AdviceMode为PROXY(默认), 则返回AutoProxyRegistrar 和 ProxyTransactionManagementConfiguration 的配置类。

源码如下:

  1. public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
  2. @Override
  3. protected String[] selectImports(AdviceMode adviceMode) {
  4. switch (adviceMode) {
  5. case PROXY:
  6. return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
  7. case ASPECTJ:
  8. return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
  9. default:
  10. return null;
  11. }
  12. }
  13. }

2. 动态注册的Bean

以@EnableAspectJAutoProxy 为例:

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Import(AspectJAutoProxyRegistrar.class)
  5. public @interface EnableAspectJAutoProxy {
  6. boolean proxyTargetClass() default false;
  7. boolean exposeProxy() default false;
  8. }

AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口,ImportBeanDefinitionRegistrar的作用是在运行时自动添加Bean到已有的配置类,并在Spring容器启动时解析生成bean,通过重写方法:

public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry)

来实现扫描注册逻辑。其中,AnnotationMetadata参数用来获得当前配置类上的注解,BeanDefinitionRegistry 参数用来注册Bean。源码如下:

  1. class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
  2. @Override
  3. public void registerBeanDefinitions(
  4. AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
  5. AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
  6. AnnotationAttributes enableAspectJAutoProxy =
  7. AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
  8. if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
  9. AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
  10. }
  11. if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
  12. AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
  13. }
  14. }
  15. }

3. 直接导入配置类

以@EnableScheduling 注解为例

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Import(SchedulingConfiguration.class)
  4. @Documented
  5. public @interface EnableScheduling {
  6. }

从上面可以看到,直接导入了入配置类SchedulingConfiguration, 这个类注解了@Configuration,且注册了一个scheduledAnnotationProcessor的Bean,SchedulingConfiguration的源码如下:

  1. @Configuration
  2. @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
  3. public class SchedulingConfiguration {
  4. @Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
  5. @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
  6. public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {
  7. return new ScheduledAnnotationBeanPostProcessor();
  8. }
  9. }

总结: 其实上面的三种方法中,第一类是用的最多的。

Spring4-@Enable** 注解的实现原理的更多相关文章

  1. Spring高级特性之三:@Enable*注解的工作原理

    Spring Boot中阐述热插拔技术的时候,简单地提及@Enable*注解.随着多种框架的应用及深入了解,@Enable*这个注解在各种框架中应用相当普及. 那么@Enable*注解工作原理是怎么样 ...

  2. Spring高级话题-@Enable***注解的工作原理

    出自:http://blog.csdn.net/qq_26525215 @EnableAspectJAutoProxy @EnableAspectJAutoProxy注解 激活Aspect自动代理 & ...

  3. Spring的@Enable*注解的工作原理

    转自:https://blog.csdn.net/chengqiuming/article/details/81586948 一 列举几个@Enable*注解的功能 @EnableAspectJAut ...

  4. springBoot @Enable*注解的工作原理

    使用注解实现异步 RunnableDemo类 package com.boot.enable.bootenable; import org.springframework.scheduling.ann ...

  5. @Enable*注解的工作原理

    @EnableAspectJAutoProxy @EnableAsync @EnableScheduling @EnableWebMv @EnableConfigurationProperties @ ...

  6. 自定义Spring-Boot @Enable注解

    Spring-Boot中有很多Enable开头的注解,通过添加注解来开启一项功能,如 其原理是什么?如何开发自己的Enable注解? 1.原理 以@EnableScheduling为例,查看其源码,发 ...

  7. Spring Boot @Enable*注解源码解析及自定义@Enable*

      Spring Boot 一个重要的特点就是自动配置,约定大于配置,几乎所有组件使用其本身约定好的默认配置就可以使用,大大减轻配置的麻烦.其实现自动配置一个方式就是使用@Enable*注解,见其名知 ...

  8. Spring Enable* 注解

    Spring提供了一系列以Enable开头的注解,这些注解本质上是激活Spring的某些管理功能.比如,EnableWebMvc. 这个注解引入了MVC框架在Spring 应用中需要用到的所有bean ...

  9. Spring 3.1新特性之二:@Enable*注解的源码,spring源码分析之定时任务Scheduled注解

    分析SpringBoot的自动化配置原理的时候,可以观察下这些@Enable*注解的源码,可以发现所有的注解都有一个@Import注解.@Import注解是用来导入配置类的,这也就是说这些自动开启的实 ...

  10. SpringBoot中神奇的@Enable*注解?

    在SpringBoot开发过程,我们经常会遇到@Enable开始的好多注解,比如@EnableEurekaServer.@EnableAsync.@EnableScheduling等,今天我们就来分析 ...

随机推荐

  1. WEUI控件JS用法

    /* dialog */ document.querySelector('#alertBtn').addEventListener('click', function () { _weui2.defa ...

  2. 嫁给程序员的好处,你get到了吗?

    首先,我们要知道,什么是程序员?程序员是做什么的? "程序员(英文Programmer)是从事程序开发.维护的专业人员.一般将程序员分为程序设计人员和程序编码人员,但两者的界限并不非常清楚, ...

  3. 【BZOJ3697】采药人的路径 点分治

    [BZOJ3697]采药人的路径 Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是 ...

  4. vue安装教程总结

    转载:https://blog.csdn.net/sunny1660/article/details/78326548 简介:       vue.js是一套构建用户界面的渐进式框架.比较简洁,用于解 ...

  5. CSS强制英文、中文换行与不换行

    .p1{ word-break:break-all; width:150px;}/*只对英文起作用,以字母作为换行依据*/ .p2{ word-wrap:break-word; width:150px ...

  6. 线段树模板(hdu1166)

    #include <set> #include <map> #include <queue> #include <stack> #include < ...

  7. mybatis执行批量更新数据

    1.业务需求:同时执行多记录批量操作 2.实现方法:     1)mapping: 2) dao 层 3)Service 层(注意要使用Transactional,否则可能会导致数据紊乱) 4)Con ...

  8. java基础梳理--朝花夕拾(三)

    1.了解面向对象的编程思想以及面向对象的特性: 对象: EveryThing is Object: 万物皆是对象,在程序中,我们可以将类.接口.方法.属性等都认为是对象: 面向对象: 是一种程序设计方 ...

  9. ASP.NET MVC - 处理Html数据

    HtmlAgilityPack 使用HtmlAgilityPack可以以面向对象的方式通过查找Html节点来获取页面元素.参考:http://html-agility-pack.net HtmlDoc ...

  10. centos系统下安装python3以及pip3

    首先查看一下系统当前的python版本 python -V 1.安装必要工具 yum-utils 它的功能是管理repository及扩展包的工具yum install yum-utils -y 2. ...