Spring Boot自动配置原理分析

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

一、写在前面

随着时间的迁移Spring Boot 越来越多的出现在Java 后端程序员的视野中,Spring Boot 之所以会那么流行,很大的一个原因是自身集成了很多的Bean,简化了传统Sring 项目琐碎的文件配置。

这些自动配置的Bean 在入口类启动的时候完成注入,并由Spring 的IoC 容器管理。所以在使用某些Bean的时候,不需要再由我们自动配置。下面我们就通过源码的方式来看看Spring Boot 是如何实现自动配置的。

二、查看自动配置的Bean

我们可以在Spring Boot 项目的配置文件(application.propertiesapplication.yml)中设置一个属性debug=true,设置完成后再启动Spring Boot 的入口类,就会在控制台输出有哪些Bean 已经完成了自动配置。

简单的截了一些如下图:
20191102100763\_1.png

三、自动配置的原理分析

1.我们从入口类开始分析,我们都知道Spring Boot 项目一般会有一个入口类,这个入口类有一个很重要的特征就是加上了@SpringBootApplication注解。

@SpringBootApplication 是一个组合注解,如下:

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan

其中有一个重要的注解@EnableAutoConfiguration,这个注解的作用就是用于启用Spring Boot 的自动配置。

2.接着具体查看@EnableAutoConfiguration,其实它也是一个组合注解,如下:

    @SuppressWarnings("deprecation")
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import(EnableAutoConfigurationImportSelector.class)

有一个注解@Import(EnableAutoConfigurationImportSelector.class),在这个注解中有一个导入自动配置的选择器,用于导入自动配置的Bean。

下面就来分析这个EnableAutoConfigurationImportSelector都做了什么。

3.EnableAutoConfigurationImportSelector类继承自AutoConfigurationImportSelector,在这个类中只有一个方法,用于判断是否启动了自动配置。

    @Deprecated
    public class EnableAutoConfigurationImportSelector extends AutoConfigurationImportSelector {

        @Override
        protected boolean isEnabled(AnnotationMetadata metadata) {
            if (getClass().equals(EnableAutoConfigurationImportSelector.class)) {
                return getEnvironment().getProperty(
                        EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class,
                        true);
            }
            return true;
        }

    }

那么我们就来看看它的父类AutoConfigurationImportSelector

4.在AutoConfigurationImportSelector类中有一个selectImports()方法,如下:

        @Override
        public String[] selectImports(AnnotationMetadata annotationMetadata) {
            if (!isEnabled(annotationMetadata)) {
                return NO_IMPORTS;
            }
            try {
                AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
                        .loadMetadata(this.beanClassLoader);
                AnnotationAttributes attributes = getAttributes(annotationMetadata);
                // 用于获取自动配置的相关信息
                List<String> configurations = getCandidateConfigurations(annotationMetadata,
                        attributes);
                configurations = removeDuplicates(configurations);
                configurations = sort(configurations, autoConfigurationMetadata);
                /** * 获得移除的自动配置信息 * 如果我们不想让Spring Boot 自动配置一些Bean, 我们可以使用在入口类的注解中使用exclude 声明 * 比如:@SpringBootApplication(exclude = {DispatcherServlet.class}) */
                Set<String> exclusions = getExclusions(annotationMetadata, attributes);
                checkExcludedClasses(configurations, exclusions);
                configurations.removeAll(exclusions);
                configurations = filter(configurations, autoConfigurationMetadata);
                fireAutoConfigurationImportEvents(configurations, exclusions);
                return configurations.toArray(new String[configurations.size()]);
            }
            catch (IOException ex) {
                throw new IllegalStateException(ex);
            }
        }

我们主要查看上面方法中的getCandidateConfigurations(annotationMetadata, attributes)方法,

        protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
                AnnotationAttributes attributes) {
            // 调用SpringFactoriesLoader 的loadFactoryNames() 方法,返回从类路径下获得自动配置相关的信息
            List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
                    getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
            // 判断自动配置的信息是否为空,为空抛出异常,第二个参数为抛出的异常信息
            Assert.notEmpty(configurations,
                    "No auto configuration classes found in META-INF/spring.factories. If you "
                            + "are using a custom packaging, make sure that file is correct.");
            return configurations;
        }

下面接着查看loadFactoryNames()方法,

        public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
            // factoryClass = EnableAutoConfiguration.class,可以通过上一步查看
            String factoryClassName = factoryClass.getName();
            try {
                /** * FACTORIES_RESOURCE_LOCATION 是一个编译器期量值为:"META-INF/spring.factories" * 用于获得所有jar 包类路径下的META-INF下的spring.factories 文件的URL */
                Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                        ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
                List<String> result = new ArrayList<String>();
                while (urls.hasMoreElements()) {
                    URL url = urls.nextElement();
                    // 将扫面到文件中的内容包装成一个Properties 对象
                    Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
                    /** * 获取EnableAutoConfiguration 类名在properties 中的值 * 这些值对应的Bean 就是要添加到Spring 容器中的自动配置类 */
                    String factoryClassNames = properties.getProperty(factoryClassName);
                    result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
                }
                return result;
            }
            catch (IOException ex) {
                throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
                        "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
            }
        }

到这里就可知道Spring Boot 是如何实现自动配置的了,Spring Boot 会扫描到类路径下的META-INF/spring.factories配置文件,把EnableAutoConfiguration对应的的Bean值添加到容器中。

5.接着我们就来看一下类路径下META-INF/spring.factories配置文件,其中EnableAutoConfiguration对应的值都是有哪些。
20191102100763\_2.png

下面是spring.factories配置文件中EnableAutoConfiguration对应的值,为了显示的效果在这里只贴出一部分。我们可以发现一个规律,这些值一般都是以×××AutoConfiguration命名,每一个×××AutoConfiguration 都作为容器中的一个组件,被添加到IoC 容器中,从而实现Spring Boot 的自动配置。


    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
    org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
    org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
    org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
    org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
    org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
    org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\

四、总结

这篇博文简单的分析了Spring Boot 自动配置的原理,给大家提供一个参考的方向,关于其中的一些具体细节,大家可以自己查看底层的源码进行了解,希望本篇博文能够为你提供帮助。


来源:http://ddrv.cn

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » Spring Boot自动配置原理分析

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏