在SpringBoot开发过程,我们经常会遇到@Enable开始的好多注解,比如@EnableEurekaServer、@EnableAsync、@EnableScheduling等,今天我们就来分析下这些注解到底是如何工作的?

本文目录

一、@Enable*实现的原理二、@Import注解的用法1. 直接导入配置类2. 依据条件选择配置类3. 动态注册Bean

一、@Enable*实现的原理

通过这些@Enable*注解的源码可以看出,所有@Enable*注解里面都有一个@Import注解,而@Import是用来导入配置类的,所以@Enable*自动开启的实现原理其实就是导入了一些自动配置的Bean。

二、@Import注解的用法

@Import注解允许导入@Configuration类,ImportSelector和ImportBeanDefinitionRegistrar的实现类,等同于正常的组件类。

有以下三种使用方式

1. 直接导入配置类

@EnableEurekaServer使用了这种方式,注解源码如下:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({EurekaServerMarkerConfiguration.class})
public @interface EnableEurekaServer {
}

可以看到@EnableEurekaServer注解直接导入了配置类EurekaServerMarkerConfiguration,而这个配置类中向spring容器中注册了一个EurekaServerMarkerConfiguration的Bean。

EurekaServerMarkerConfiguration的源码如下:

@Configuration
public class EurekaServerMarkerConfiguration {
    public EurekaServerMarkerConfiguration() {
    }     @Bean
    public EurekaServerMarkerConfiguration.Marker eurekaServerMarkerBean() {
        return new EurekaServerMarkerConfiguration.Marker();
    }     class Marker {
        Marker() {
        }
    }
}

2. 依据条件选择配置类

@EnableAsync使用了这种方式,注解源码如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {     Class<? extends Annotation> annotation() default Annotation.class;     boolean proxyTargetClass() default false;     AdviceMode mode() default AdviceMode.PROXY;     int order() default Ordered.LOWEST_PRECEDENCE;
}

EnableAsync注解中导入了AsyncConfigurationSelector,AsyncConfigurationSelector通过条件来选择需要导入的配置类,继承AdviceModeImportSelector又实现了ImportSelector接口,接口重写selectImports方法进行事先条件判断PROXY或者ASPECTJ选择不同的配置类。

AsyncConfigurationSelector源码如下:

public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {

    private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME =
            "org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";     /**
     * Returns {@link ProxyAsyncConfiguration} or {@code AspectJAsyncConfiguration}
     * for {@code PROXY} and {@code ASPECTJ} values of {@link EnableAsync#mode()},
     * respectively.
     */
    @Override
    @Nullable
    public String[] selectImports(AdviceMode adviceMode) {
        switch (adviceMode) {
            case PROXY:
                return new String[] {ProxyAsyncConfiguration.class.getName()};
            case ASPECTJ:
                return new String[] {ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME};
            default:
                return null;
        }
    } }

3. 动态注册Bean

@EnableAspectJAutoProxy使用了这种方式,注解源码如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {     boolean proxyTargetClass() default false;     boolean exposeProxy() default false;
}

EnableAspectJAutoProxy注解中导入了AspectJAutoProxyRegistrar,AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口,在运行时把Bean注册到spring容器中。

AspectJAutoProxyRegistrar的源码如下:

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

    /**
     * Register, escalate, and configure the AspectJ auto proxy creator based on the value
     * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
     * {@code @Configuration} class.
     */
    @Override
    public void registerBeanDefinitions(
            AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {         AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);         AnnotationAttributes enableAspectJAutoProxy =
                AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
        if (enableAspectJAutoProxy != null) {
            if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }
            if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
                AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
            }
        }
    } }

推荐阅读

1.Java中Integer.parseInt和Integer.valueOf,你还傻傻分不清吗?
2.SpringCloud系列-整合Hystrix的两种方式)
3.SpringCloud系列-利用Feign实现声明式服务调用)
4.手把手带你利用Ribbon实现客户端的负载均》
5.SpringCloud搭建注册中心与服务注册


限时领取免费Java相关资料,涵盖了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo/Kafka、Hadoop、Hbase、Flink等高并发分布式、大数据、机器学习等技术。
关注下方公众号即可免费领取:

Java碎碎念公众号

SpringBoot中神奇的@Enable*注解?的更多相关文章

  1. springboot中@EnableAsync与@Async注解使用

    springboot中@EnableAsync与@Async注解使用 @Async为异步注解,放到方法上,表示调用该方法的线程与此方法异步执行,需要配合@EnableAsync注解使用. 1.首先演示 ...

  2. Springboot中使用自定义参数注解获取 token 中用户数据

    使用自定义参数注解获取 token 中User数据 使用背景 在springboot项目开发中需要从token中获取用户信息时通常的方式要经历几个步骤 拦截器中截获token TokenUtil工具类 ...

  3. 在Spring-boot中,为@Value注解添加从数据库读取properties支持

    一般我们会把常用的属性放在工程的classpath文件夹中,以property,yaml或json的格式进行文件存储,便于Spring-boot在初始化时获取. @Value则是Spring一个非常有 ...

  4. Spring中的@Enable注解

    本文转载自SpringBoot中神奇的@Enable注解? 导语 在SpringBoot开发过程,我们经常会遇到@Enable开始的好多注解,比如@EnableEurekaServer.@Enable ...

  5. SpringBoot中如何灵活的实现接口数据的加解密功能?

    数据是企业的第四张名片,企业级开发中少不了数据的加密传输,所以本文介绍下SpringBoot中接口数据加密.解密的方式. 本文目录 一.加密方案介绍二.实现原理三.实战四.测试五.踩到的坑 一.加密方 ...

  6. SpringBoot中如何优雅的读取yml配置文件?

    YAML是一种简洁的非标记语言,以数据为中心,使用空白.缩进.分行组织数据,从而使得表示更加简洁易读.本文介绍下YAML的语法和SpringBoot读取该类型配置文件的过程. 本文目录 一.YAML基 ...

  7. SpringBoot 中定时执行注解(@Scheduled、@EnableScheduling)

    项目开发中经常需要执行一些定时任务,比如需要在每天凌晨时候,分析一次前一天的日志信息.Spring为我们提供了异步执行任务调度的方式,提供TaskExecutor .TaskScheduler 接口. ...

  8. [SpringBoot]SpringBoot中使用redis事务

    本文基于SpringBoot 2.X 事务在关系型数据库的开发中经常用到,其实非关系型数据库,比如redis也有对事务的支持,本文主要探讨在SpringBoot中如何使用redis事务. 事务的相关介 ...

  9. SpringBoot中关于@Enable***的注解详解

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

随机推荐

  1. CODESYS添加target

    1.主界面进入Tools 2.Install,选择安装包

  2. 右键没有新建word选项

    两类解决办法 一. 1. 新建一个txt文本,并插入如下内容: Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\.doc] @=&quo ...

  3. 03 (OC)* UITableView优化

    一:cell注册和初始化 1:不注册cell 2:注册类 3:注册nib 4:storyboard 二:核心思想 1:UITableView的核心思想是:cell的重用机制.UITbleView只会创 ...

  4. ELK7.3实战安装配置文档

    整体架构   一:环境准备 1.环境规划准备 192.168.43.16 jdk,elasticsearch-master ,logstash,kibana 192.168.43.17 jdk,ela ...

  5. Spring boot 官网学习笔记 - Spring Boot 属性配置和使用(转)-application.properties

    Spring Boot uses a very particular PropertySource order that is designed to allow sensible overridin ...

  6. 问题:程序编译通过,但是执行时报错:coredump

    问题描述: 在一个客户现场搭建环境时,遇到了一个棘手的问题,C代码编译通过后,无法正常运行,启动会出现“coredump”错误. 运行环境为新搭建的AIX6.1,数据库为Oracle11.2.0.2. ...

  7. 链表常见的题型(java实现)

    链表是面试中最常见的一种题型,因为他的每个题的代码短,短短的几行代码就可以体现出应聘者的编码能力,所以它也就成为了面试的重点. 链表常见的操作有1.打印链表的公共部分,2.删除链表的倒数第K个节点,3 ...

  8. ES6学习总结之Set和Map数据结构的理解

    前言 当我们需要存储一些数据的时候,首先想到的是定义一个变量用来存储,之后我们可能学了数组,发现数组比变量可以存储更多的数据,接着可能有其它的存储数据的方法等等,然而我今天需要介绍的是在ES6中比较常 ...

  9. 五 mysql之多表查询

    目录 一 介绍 二 多表连接查询 1.交叉连接:不适用任何匹配条件.生成笛卡尔积 2.内连接:只连接匹配的行 3 .外链接之左连接:优先显示左表全部记录 4 .外链接之右连接:优先显示右表全部记录 5 ...

  10. ng执行css3动画

    在组件html中 <div> <aside id="aside">侧边栏</aside> <div class="content ...