閱讀本文前,請(qǐng)先閱讀作者的另一篇文章Spring-Boot之@Enable*注解的工作原理
@EnableAutoConfiguration作用:從classpath中搜索所有的META-INF/spring.factories配置文件,然后將其中key為org.springframework.boot.autoconfigure.EnableAutoConfiguration的value加載到spring容器中
首先我們來做一個(gè)小實(shí)驗(yàn):
1、創(chuàng)建一個(gè)spring項(xiàng)目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、創(chuàng)建一個(gè)spring-boot項(xiàng)目blog,引入剛剛創(chuàng)建的外部項(xiàng)目jianshu-starter
//...
<dependency>
<groupId>com.bamu.jianshu</groupId>
<artifactId>jianshu-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
//...
4、在blog項(xiàng)目中編寫啟動(dòng)類BlogApplication
@SpringBootApplication
public class BlogApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(BlogApplication.class, args);
//獲取jianshu-starter項(xiàng)目中定義的bean runnable
System.out.println(context.getBean("runnable").getClass().getName());
context.close();
}
}
5、啟動(dòng)

咦?
@SpringBootApplication注解中不是為我們配置了@EnableAutoConfiguration了嗎?為什么這里獲取不到外部項(xiàng)目注入到spring容器中的bean呢?
為了解答這個(gè)疑惑,我們查閱@EnableAutoConfiguration注解中import進(jìn)去的Selector的源碼,追溯到AutoConfigurationImportSelector這個(gè)類后,我們發(fā)現(xiàn)了getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes)這個(gè)方法。

紅框中的英文翻譯后意思為:在META-INF / spring.factories中找不到自動(dòng)配置類。 如果您使用自定義打包,請(qǐng)確保文件正確無誤。
繼續(xù)帶著疑惑,我們?cè)囍c(diǎn)進(jìn)loadFactoryNames這個(gè)方法中去一探究竟:

噢,原來,這個(gè)方法通過是ClassLoader,去我們的classpath目錄下的META-INF/spring.factoried文件中去查找以EnableAutoConfiguration這個(gè)類的全類名為key的值,然后把它們add到一個(gè)集合當(dāng)中return出去。看完這個(gè)方法的源碼后,我們回到上一個(gè)截圖
getCandidateConfigurations方法的源碼,發(fā)現(xiàn)他在做了一個(gè)非空校驗(yàn)后,接著往上層返回。那我們找到調(diào)用getCandidateConfigurations方法的代碼看看。

我們追溯到了
selectImports這個(gè)方法。閱讀過Spring-Boot之@Enable*注解的工作原理這篇文章的讀者肯定一下就看明白了,噢,原來這個(gè)方法獲取到了List<String> configurations這個(gè)集合后,通過removeDuplicates方法做了去重、通過sort方法做了排序、通過getExclusions這個(gè)方法做了排除(那我們排除的依據(jù)從哪來呢?大家可以打開@EnableAutoConfiguration注解的源碼一看便知,該注解給我們提供了兩種方式排除我們不想注入到spring容器中的bean)......最后將configurations這個(gè)集合轉(zhuǎn)為String[]返回,通過推薦的文章我們知道,selectImports()方法返回出去的數(shù)組是會(huì)被spring容器托管的,這下我們?nèi)懒耍?br>
在springboot項(xiàng)目中,其他包下自動(dòng)裝配的bean,是需要在classpath下的META-INF/spring.factories文件中配置,才能被spring容器注入
so,我們按照springboot的要求,創(chuàng)建一個(gè)spring.factories并配置我們需要獲取的bean runnable


提醒一下:由
loadFactoryNames和selectImports方法的源碼我們發(fā)現(xiàn),key必須是EnableAutoConfiguration注解的全類名,value必須是你想自動(dòng)裝配的bean的全類名再執(zhí)行BlogApplication類試一試:

完美地獲取到了runnable這個(gè)對(duì)象
另外,拓展一下springboot為我們提供的starter包如何實(shí)現(xiàn)開箱即用。事實(shí)上,我們看到的springboot提供的starter包,都引用了很多我們比較熟悉的jar包,它也是通過我在上文中介紹的方式,將它想要注入的bean,配置到spring.factories文件中。例如:

我們打開spring.factories文件看一看

看看,spring-boot-autoconfiguration這個(gè)項(xiàng)目注入了這么多其他項(xiàng)目的bean。
以上,就是Spring-boot @EnableAutoConfiguration源碼分析的全部?jī)?nèi)容,望讀者帶著批判的心態(tài)閱讀我的文章,發(fā)現(xiàn)錯(cuò)誤,麻煩直接評(píng)論,共同學(xué)習(xí),共同進(jìn)步。
也可以觀看spring-boot系列的其他文章,都是干貨喲~