閱讀本文前,請先閱讀作者的另一篇文章Spring-Boot之@Enable*注解的工作原理
@EnableAutoConfiguration作用:從classpath中搜索所有的META-INF/spring.factories配置文件夹抗,然后將其中key為org.springframework.boot.autoconfigure.EnableAutoConfiguration的value加載到spring容器中
首先我們來做一個小實驗:
1、創(chuàng)建一個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极舔、創(chuàng)建一個spring-boot項目blog,引入剛剛創(chuàng)建的外部項目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、啟動
咦?
@SpringBootApplication
注解中不是為我們配置了@EnableAutoConfiguration
了嗎慈俯?為什么這里獲取不到外部項目注入到spring容器中的bean呢渤刃?
為了解答這個疑惑,我們查閱@EnableAutoConfiguration
注解中import進去的Selector的源碼贴膘,追溯到AutoConfigurationImportSelector
這個類后卖子,我們發(fā)現(xiàn)了getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes)
這個方法。
紅框中的英文翻譯后意思為:在META-INF / spring.factories中找不到自動配置類刑峡。 如果您使用自定義打包洋闽,請確保文件正確無誤。
繼續(xù)帶著疑惑突梦,我們試著點進loadFactoryNames
這個方法中去一探究竟:
噢诫舅,原來,這個方法通過是ClassLoader宫患,去我們的classpath目錄下的META-INF/spring.factoried文件中去查找以EnableAutoConfiguration這個類的全類名為key的值刊懈,然后把它們add到一個集合當(dāng)中return出去⊥尴校看完這個方法的源碼后虚汛,我們回到上一個截圖
getCandidateConfigurations
方法的源碼,發(fā)現(xiàn)他在做了一個非空校驗后皇帮,接著往上層返回卷哩。那我們找到調(diào)用getCandidateConfigurations
方法的代碼看看。
我們追溯到了
selectImports
這個方法属拾。閱讀過Spring-Boot之@Enable*注解的工作原理這篇文章的讀者肯定一下就看明白了将谊,噢,原來這個方法獲取到了List<String> configurations
這個集合后捌年,通過removeDuplicates
方法做了去重瓢娜、通過sort
方法做了排序、通過getExclusions
這個方法做了排除(那我們排除的依據(jù)從哪來呢礼预?大家可以打開@EnableAutoConfiguration
注解的源碼一看便知眠砾,該注解給我們提供了兩種方式排除我們不想注入到spring容器中的bean)......最后將configurations
這個集合轉(zhuǎn)為String[]返回,通過推薦的文章我們知道托酸,selectImports()
方法返回出去的數(shù)組是會被spring容器托管的褒颈,這下我們?nèi)懒耍?br>
在springboot項目中,其他包下自動裝配的bean励堡,是需要在classpath下的META-INF/spring.factories文件中配置谷丸,才能被spring容器注入
so,我們按照springboot的要求应结,創(chuàng)建一個spring.factories并配置我們需要獲取的bean runnable
提醒一下:由
loadFactoryNames
和selectImports
方法的源碼我們發(fā)現(xiàn)刨疼,key必須是EnableAutoConfiguration注解的全類名泉唁,value必須是你想自動裝配的bean的全類名再執(zhí)行BlogApplication類試一試:
完美地獲取到了runnable這個對象
另外,拓展一下springboot為我們提供的starter包如何實現(xiàn)開箱即用揩慕。事實上亭畜,我們看到的springboot提供的starter包,都引用了很多我們比較熟悉的jar包迎卤,它也是通過我在上文中介紹的方式拴鸵,將它想要注入的bean,配置到spring.factories文件中蜗搔。例如:
我們打開spring.factories文件看一看
看看劲藐,spring-boot-autoconfiguration這個項目注入了這么多其他項目的bean。
以上樟凄,就是Spring-boot @EnableAutoConfiguration源碼分析的全部內(nèi)容聘芜,望讀者帶著批判的心態(tài)閱讀我的文章,發(fā)現(xiàn)錯誤不同,麻煩直接評論厉膀,共同學(xué)習(xí),共同進步二拐。
也可以觀看spring-boot系列的其他文章服鹅,都是干貨喲~