Spring boot是如何实现自动化配置的?

Spring Enable*高级应用及原理

我相信在很多的Spring boot项目中都大量使用到了以Enable*的注解。
比如EnableAsync、EnableScheduling、EnableAspectJAutoProxy、EnableCaching等,Enable表示开启/允许一项功能。

Enable*工作原理
我们只需要几个很简单的注解就能开启一个复杂的功能,这是多么简易的用法,这是怎么办到的?

首先来看看计划任务@EnableScheduling的源代码

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(SchedulingConfiguration.class)
@Documented
public @interface EnableScheduling {

}

主要核心的配置就是导入了一个配置文件:

@Import(SchedulingConfiguration.class)

1、Configuration

即上面的用法,直接导入Configuration配置类。

2、ImportSelector

根据条件选择导入不同的配置类,参考@EnableAsync

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {
    private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME =
            "org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";

    /**
     * {@inheritDoc}
     * @return {@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、ImportBeanDefinitionRegistrar
动态注册Bean,参考@EnableAspectJAutoProxy

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

    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);
            }
        }
    }

}

简单实现一个自动化配置Demo
该starter提供PersonService,并实现自动配置PersonService

1、创建一个Spring boot 项目
2、引入所需要的jar包
Spring boot是如何实现自动化配置的?_第1张图片

3、创建需要自动配置的人员信息的实体
Spring boot是如何实现自动化配置的?_第2张图片

4、创建服务类
Spring boot是如何实现自动化配置的?_第3张图片

5、编写自动注入类
Spring boot是如何实现自动化配置的?_第4张图片

6、.注册配置
1.在src/main/resources新建META-INF文件夹
2.在META-INF文件夹下创建spring.factories文件
3.注册配置自动配置信息,内容如下
这里写图片描述

7、使用maven 将starter安装到本地
8、创建一个新的spring boot 项目并使用已创建好starter
Spring boot是如何实现自动化配置的?_第5张图片

9、在新项目的启动类上指定开启需要自动配置的类
Spring boot是如何实现自动化配置的?_第6张图片

10、在新项目的配置文件中引入需要进行配置的属性
这里写图片描述

11、然后创建访问测试的接口
Spring boot是如何实现自动化配置的?_第7张图片

12、最后启动并进行测试
Spring boot是如何实现自动化配置的?_第8张图片

在构建starter的过程中,涉及到一些注解

@ConditionalOnBean:当容器中有指定的Bean的条件下
@ConditionalOnClass:当类路径下有指定的类的条件下
@ConditionalOnExpression:基于SpEL表达式作为判断条件
@ConditionalOnJava:基于JVM版本作为判断条件
@ConditionalOnJndi:在JNDI存在的条件下查找指定的位置
@ConditionalOnMissingBean:当容器中没有指定Bean的情况下
@ConditionalOnMissingClass:当类路径下没有指定的类的条件下
@ConditionalOnNotWebApplication:当前项目不是Web项目的条件下
@ConditionalOnProperty:指定的属性是否有指定的值
@ConditionalOnResource:类路径下是否有指定的资源
@ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个,或者在有多个Bean的情况下,用来指定首选的Bean
@ConditionalOnWebApplication:当前项目是Web项目的条件下

你可能感兴趣的:(spring,boot)