demo
自己定義一個(gè)外部項(xiàng)目奴紧,core-bean搪花,依賴(lài)如下,
<artifactId>core-bean</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
</dependencies>
然后定義一個(gè)Cat類(lèi)薯嗤,
public class Cat {
}
package core.bean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyConfig {
@Bean
public Cat cat(){
return new Cat();
}
}
我們知道這樣就將Cat類(lèi)裝配到Spring容器了顽爹。
再定義一個(gè)springboot項(xiàng)目,加入core-bean依賴(lài)骆姐,依賴(lài)如下:
<artifactId>springboot-enableAutoConfiguration</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.zhihao.miao</groupId>
<artifactId>core-bean</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
啟動(dòng)類(lèi)啟動(dòng):
@EnableAutoConfiguration
@ComponentScan
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context =SpringApplication.run(Application.class,args);
Cat cat = context.getBean(Cat.class);
System.out.println(cat);
}
}
發(fā)現(xiàn)Cat類(lèi)并沒(méi)有納入到springboot-enableAutoConfiguration項(xiàng)目中镜粤。
解決方案,
在core-bean項(xiàng)目resource下新建文件夾META-INF玻褪,在文件夾下面新建spring.factories文件肉渴,文件中配置,key為自定配置類(lèi)EnableAutoConfiguration的全路徑带射,value是配置類(lèi)的全路徑
org.springframework.boot.autoconfigure.EnableAutoConfiguration=core.bean.MyConfig
啟動(dòng)springboot-enableAutoConfiguration項(xiàng)目同规,打印結(jié)果:
原理分析
進(jìn)入EnableAutoConfiguration注解源碼,發(fā)現(xiàn)是導(dǎo)入EnableAutoConfigurationImportSelector類(lèi)窟社,
跟到最后發(fā)現(xiàn)繼承了ImportSelector接口券勺,之前我們講過(guò)Springboot @Enable*注解的工作原理ImportSelector接口的selectImports返回的數(shù)組(類(lèi)的全類(lèi)名)都會(huì)被納入到spring容器中。
其在AutoConfigurationImportSelector類(lèi)中的selectImports實(shí)現(xiàn)灿里,進(jìn)入org.springframework.boot.autoconfigure.AutoConfigurationImportSelector類(lèi)关炼,
進(jìn)入getCandidateConfigurations方法
getCandidateConfigurations會(huì)到classpath下的讀取META-INF/spring.factories文件的配置,并返回一個(gè)字符串?dāng)?shù)組匣吊。
調(diào)試的時(shí)候讀取到了core.bean.MyConfig儒拂,也讀到了一些其他的配置,下面會(huì)講色鸳。
具體的就不細(xì)說(shuō)了社痛,有興趣的朋友可以自己調(diào)試一下。
META-INF/spring.factories還可以配置多個(gè)配置類(lèi)命雀。
比如我們?cè)赾ore-bean下在定義二個(gè)類(lèi)蒜哀,
package core.bean;
public class Dog {
}
package core.bean;
public class People {
}
package core.bean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Myconfig2 {
@Bean
public Dog dog(){
return new Dog();
}
}
修改META-INF/spring.factories下的配置,
org.springframework.boot.autoconfigure.EnableAutoConfiguration=core.bean.MyConfig,core.bean.Myconfig2,core.bean.People
修改springboot-enableAutoConfiguration項(xiàng)目的啟動(dòng)類(lèi):
package com.zhihao.miao;
import core.bean.Cat;
import core.bean.Dog;
import core.bean.People;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
@EnableAutoConfiguration
@ComponentScan
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context =SpringApplication.run(Application.class,args);
Cat cat = context.getBean(Cat.class);
System.out.println(cat);
Dog dog = context.getBean(Dog.class);
System.out.println(dog);
People people = context.getBean(People.class);
System.out.println(people);
}
}
打印結(jié)果如下:
發(fā)現(xiàn)都納入到spring容器中了咏雌。
可以配置spring.boot.enableautoconfiguration=false禁用自動(dòng)配置凡怎,這樣不會(huì)啟動(dòng)自動(dòng)配置了校焦,默認(rèn)是true。還可以排出一些自動(dòng)配置類(lèi)统倒,可以在EnableAutoConfiguration注解加入?yún)?shù)寨典,這邊不做過(guò)多解釋。
總結(jié),@EnableAutoConfiguration 作用
從classpath中搜索所有META-INF/spring.factories配置文件然后房匆,將其中org.springframework.boot.autoconfigure.EnableAutoConfiguration key對(duì)應(yīng)的配置項(xiàng)加載到spring容器
只有spring.boot.enableautoconfiguration為true(默認(rèn)為true)的時(shí)候耸成,才啟用自動(dòng)配置
@EnableAutoConfiguration還可以進(jìn)行排除,排除方式有2中浴鸿,一是根據(jù)class來(lái)排除(exclude)井氢,二是根據(jù)class name(excludeName)來(lái)排除
其內(nèi)部實(shí)現(xiàn)的關(guān)鍵點(diǎn)有
1)ImportSelector 該接口的方法的返回值都會(huì)被納入到spring容器管理中
2)SpringFactoriesLoader 該類(lèi)可以從classpath中搜索所有META-INF/spring.factories配置文件,并讀取配置
springboot內(nèi)部如何使用@EnableAutoConfiguration注解
我們點(diǎn)進(jìn)去spring-boot-autoconfigure中的META-INF下的spring.factories文件岳链,發(fā)現(xiàn)spring.factories文件中配置了好多的配置類(lèi)花竞,在將這些依賴(lài)依賴(lài)到自己的項(xiàng)目中會(huì)將其都納入到spring容器中,不過(guò)這些類(lèi)好多都是配合@Conditional***等注解一起工作的掸哑。
舉個(gè)例子:
在springboot-enableAutoConfiguration加入Gson依賴(lài):
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
如果我們不在項(xiàng)目中配置约急,spring-boot-autoconfigure會(huì)自動(dòng)幫我們裝配一個(gè)對(duì)象實(shí)例名為gson的Gson實(shí)例。如果自己裝配那么就使用自己裝配的Gson實(shí)例苗分。
啟動(dòng)測(cè)試類(lèi):
package com.zhihao.miao;
import com.google.gson.Gson;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context =SpringApplication.run(Application.class,args);
System.out.println(context.getBeansOfType(Gson.class));
}
}
此時(shí)自己沒(méi)有去配置Gson對(duì)象厌蔽,
如果自己配置了,測(cè)試代碼如下摔癣,啟動(dòng):
package com.zhihao.miao;
import com.google.gson.Gson;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class Application {
@Bean
public Gson createGson(){
return new Gson();
}
public static void main(String[] args) {
ConfigurableApplicationContext context =SpringApplication.run(Application.class,args);
System.out.println(context.getBeansOfType(Gson.class));
}
}