Spring-boot @EnableAutoConfiguration源码分析

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

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

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】
免费领取 2000+ 道 Java 面试题

阅读本文前,请先阅读作者的另一篇文章Spring-Boot之@Enable*注解的工作原理

@EnableAutoConfiguration作用:从classpath中搜索所有的META-INF/spring.factories配置文件,然后将其中key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的value加载到spring容器中

首先我们来做一个小实验:
1、创建一个spring项目jianshu-starter

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>

        <groupId>com.bamu.jianshu</groupId>
        <artifactId>jianshu-starter</artifactId>
        <version>1.0-SNAPSHOT</version>

        <name>jianshu-starter</name>
        <description>The first Spring Boot project</description>

        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <maven.compiler.source>1.8</maven.compiler.source>
            <maven.compiler.target>1.8</maven.compiler.target>
        </properties>

        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>4.3.11.RELEASE</version>
            </dependency>
        </dependencies>

        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>

2、编写configuration类,注入到spring容器中

    @Configuration
    public class RunnableConfiguration {
        @Bean
        public Runnable runnable() {
            return () -> {};
        }
    }

3、创建一个spring-boot项目blog,引入刚刚创建的外部项目jianshu-starter

    //...
    <dependency>
          <groupId>com.bamu.jianshu</groupId>
          <artifactId>jianshu-starter</artifactId>
          <version>1.0-SNAPSHOT</version>
    </dependency>
    //...

4、在blog项目中编写启动类BlogApplication

    @SpringBootApplication
    public class BlogApplication {
        public static void main(String[] args) {
            ConfigurableApplicationContext context = SpringApplication.run(BlogApplication.class, args);
            //获取jianshu-starter项目中定义的bean runnable
            System.out.println(context.getBean("runnable").getClass().getName());
            context.close();
        }
    }

5、启动

2019101710072\_1.png

console result

咦?@SpringBootApplication注解中不是为我们配置了@EnableAutoConfiguration了吗?为什么这里获取不到外部项目注入到spring容器中的bean呢?

为了解答这个疑惑,我们查阅@EnableAutoConfiguration注解中import进去的Selector的源码,追溯到AutoConfigurationImportSelector这个类后,我们发现了getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes)这个方法。

2019101710072\_2.png

getCandidateConfigurations方法

红框中的英文翻译后意思为:在META-INF / spring.factories中找不到自动配置类。 如果您使用自定义打包,请确保文件正确无误。

继续带着疑惑,我们试着点进loadFactoryNames这个方法中去一探究竟:

2019101710072\_3.png

loadFactoryNames方法

噢,原来,这个方法通过是ClassLoader,去我们的classpath目录下的META-INF/spring.factoried文件中去查找以EnableAutoConfiguration这个类的全类名为key的值,然后把它们add到一个集合当中return出去。看完这个方法的源码后,我们回到上一个截图getCandidateConfigurations方法的源码,发现他在做了一个非空校验后,接着往上层返回。那我们找到调用getCandidateConfigurations方法的代码看看。

2019101710072\_4.png

selectImports方法

我们追溯到了code>selectImports这个方法。阅读过[Spring-Boot之@Enable\*注解的工作原理][Spring-Boot_Enable]这篇文章的读者肯定一下就看明白了,噢,原来这个方法获取到了List<String> configurations这个集合后,通过removeDuplicates方法做了去重、通过sort方法做了排序、通过getExclusions这个方法做了排除(那我们排除的依据从哪来呢?大家可以打开@EnableAutoConfiguration注解的源码一看便知,该注解给我们提供了两种方式排除我们不想注入到spring容器中的bean)……最后将configurations这个集合转为String[]返回,通过推荐的文章我们知道,selectImports()方法返回出去的数组是会被spring容器托管的,这下我们全知道了:
在springboot项目中,其他包下自动装配的bean,是需要在classpath下的META-INF/spring.factories文件中配置,才能被spring容器注入

so,我们按照springboot的要求,创建一个spring.factories并配置我们需要获取的bean runnable

2019101710072\_5.png

spring.factories

2019101710072\_6.png

META-INF/spring.factories

提醒一下:loadFactoryNamesselectImports方法的源码我们发现,key必须是EnableAutoConfiguration注解的全类名,value必须是你想自动装配的bean的全类名
再执行BlogApplication类试一试:

2019101710072\_7.png

console result

完美地获取到了runnable这个对象

另外,拓展一下springboot为我们提供的starter包如何实现开箱即用。事实上,我们看到的springboot提供的starter包,都引用了很多我们比较熟悉的jar包,它也是通过我在上文中介绍的方式,将它想要注入的bean,配置到spring.factories文件中。例如:

2019101710072\_8.png

spring-boot-autoconfiguration

我们打开spring.factories文件看一看

2019101710072\_9.png

spring.properties文件冰山一角

看看,spring-boot-autoconfiguration这个项目注入了这么多其他项目的bean。

以上,就是Spring-boot @EnableAutoConfiguration源码分析的全部内容,望读者带着批判的心态阅读我的文章,发现错误,麻烦直接评论,共同学习,共同进步。
也可以观看spring-boot系列的其他文章,都是干货哟~

我会把阅读到的所有知识都分享给你ʕ•̫͡•ʕ*̫͡*ʕ•͓͡•ʔ-̫͡-ʕ•̫͡•ʔ*̫͡*…

作者:八目朱勇铭
链接:
https://www.jianshu.com/p/c1c2443ed43b
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。


来源:[]()

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » Spring-boot @EnableAutoConfiguration源码分析

评论 抢沙发

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

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

支付宝扫一扫打赏

微信扫一扫打赏