zoukankan      html  css  js  c++  java
  • SpringBoot中神奇的@Enable*注解?

    在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碎碎念公众号Java碎碎念公众号

     

  • 相关阅读:
    centos7 nfs安装
    Rasa在PyCharm中进行debug
    IOS的? !
    IOS中IndexPath
    移动端文本框点击后网页变大的解决办法
    h5 在全屏iphonex中的适配
    net5中得logging保存到文件中
    SQL SERVER 2000数据库置疑处理
    ILSpy源码下载后,编译不过的问题
    Tigase8.x 搭配Mysql8及以上启动时报错(Nodes redirection table: tig_cluster_nodes doesn't exits)的解决方法
  • 原文地址:https://www.cnblogs.com/haha12/p/11730357.html
Copyright © 2011-2022 走看看