欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SpringBoot中神奇的@Enable*注解?

程序员文章站 2022-04-14 20:45:30
在SpringBoot开发过程,我们经常会遇到@Enable开始的好多注解,比如@EnableEurekaServer、@EnableAsync、@EnableScheduling等,今天我们就来分析下这些注解到底是如何工作的? 本文目录 一、@Enable*实现的原理二、@Import注解的用法1 ......

在springboot开发过程,我们经常会遇到@enable开始的好多注解,比如@enableeurekaserver、@enableasync、@enablescheduling等,今天我们就来分析下这些注解到底是如何工作的?

本文目录

一、@enable*实现的原理二、@import注解的用法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等高并发分布式、大数据、机器学习等技术。
关注下方公众号即可免费领取:

SpringBoot中神奇的@Enable*注解?java碎碎念公众号