【学习笔记】springboot的AutoConfigurationImportSelector 、@EnableAutoConfiguraion和@import解析
文章目錄
- @EnableAutoConfiguration介紹
- AutoConfigurationImportSelector
- 例子:使用importSelector
- 自動裝配原理分析
- 總結
@EnableAutoConfiguration介紹
自動裝配在Spring Boot中是通過@EnableAutoConfiguration注解來開啟的,這個注解的聲明在啟動類注解@SpringBootApplication內。 進入@SpringBootApplication注解,可以看到@EnableAutoConfiguration注解的聲明。
其實Spring 3.1版本就已經支持@Enable注解了,它的主要作用把相關組件的Bean裝配到IoC容器中。
**@Enable注解對JavaConfig的進一步完善,為使用Spring Framework的開發者減少了配置代碼量,降低了使用的難度。**比如常見的@Enable注解有@EnableWebMvc、@EnableScheduling等。
如果基于JavaConfig的形式來完成Bean的裝載,則必須要使用@Configuration注解及@Bean注解。而@Enable本質上就是針對這兩個注解的封裝,所以大家如果仔細關注過這些注解,就不難發現這些注解中都會攜帶一個@Import注解,比如@EnableScheduling:因此,使用@Enable注解后,Spring會解析到@Import導入的配置類,從而根據這個配置類中的描述來實現Bean的裝配,那么@EnableAutoConfiguraion實現原理是不是也一樣呢?
進入@EnableAutoConfiguration注解里,可以看到除@Import注解之外,還多了一個@AutoConfigurationPackage注解(它的作用是把使用了該注解的類所在的包及子包下所有組件掃描到Spring IoC容器中)。并且,**@Import注解中導入的并不是一個Configuration的配置類,而是一個AutoConfigurationImportSelector類。**從這一點來看,它就和其他的@Enable注解有很大的不同。
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";Class<?>[] exclude() default {};String[] excludeName() default {}; }AutoConfigurationImportSelector
AutoConfigurationImportSelector源碼:
public class AutoConfigurationImportSelectorimplements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,BeanFactoryAware, EnvironmentAware, Ordered {private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry();private static final String[] NO_IMPORTS = {};private static final Log logger = LogFactory.getLog(AutoConfigurationImportSelector.class);private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";private ConfigurableListableBeanFactory beanFactory;private Environment environment;private ClassLoader beanClassLoader;private ResourceLoader resourceLoader;....}它實現了DeferredImportSelector,接口,而DeferredImportSelector又繼承了ImportSelector,
package org.springframework.context.annotation;import org.springframework.core.type.AnnotationMetadata;public interface ImportSelector {String[] selectImports(AnnotationMetadata var1); }它只有一個selectImports抽象方法,并且返回一個String數組,在這個數組中可以指定需要裝配到IoC容器的類,當在@Import中導入一個ImportSelector的實現類之后,會把該實現類中返回的Class名稱都裝載到IoC容器中。 和@Configuration不同的是,ImportSelector可以實現批量裝配,并且還可以通過邏輯處理來實現Bean的選擇性裝配,也就是可以根據上下文來決定哪些類能夠被IoC容器初始化。
其中DeferredImportSelector有一個方法:
其執行邏輯是,當實現DeferredImportSelector類重寫了
public Class<? extends Group> getImportGroup()
方法時,則在此類被@Import注解導入時執行getImportGroup方法,如果沒有實現getImportGroup方法,則執行
public String[] selectImports(AnnotationMetadata importingClassMetadata)
例子:使用importSelector
1.先創建兩個類
public class FirstClass { } public class SecondClass { }2.我們需要把這兩個類裝配到IoC容器中。 ·
創建一個ImportSelector的實現類,在實現類中把定義的兩個Bean加入String數組,這意味著這兩個Bean會裝配到IoC容器中。 ·
3.為了模擬EnableAutoConfiguration,我們可以自定義一個類似的注解,通過@Import導入GpImportSelector。
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(GpImportSelector.class) public @interface MyEnableleImport { }4.· 創建一個啟動類,在啟動類上使用@EnableAutoImport注解后,即可通過getBean從IoC容器中得到FirstClass對象實例。
@MyEnableleImport @SpringBootApplicationpublic class HwMusicApplication {public static void main(String[] args) throws IOException {ConfigurableApplicationContext ca = SpringApplication.run(HwMusicApplication.class, args);FirstClass firstClass = ca.getBean(FirstClass.class);firstClass.get();//自己隨意寫的一個方法}}這種實現方式相比@Import(*Configuration.class)的好處在于裝配的靈活性,還可以實現批量。比如GpImportSelector還可以直接在String數組中定義多個Configuration類,由于一個配置類代表的是某一個技術組件中批量的Bean聲明,所以在自動裝配這個過程中只需要掃描到指定路徑下對應的配置類即可。
自動裝配原理分析
自動裝配的核心是掃描約定目錄下的文件進行解析,解析完成之后把得到的Configuration配置類通過ImportSelector進行導入,從而完成Bean的自動裝配過程。那么接下來我們通過分析AutoConfigurationImportSelector的實現來求證這個猜想是否正確。
定位到AutoConfigurationImportSelector中的selectImports方法,它是ImportSelector接口的實現,這個方法中主要有兩個功能:
· AutoConfigurationMetadataLoader.loadMetadata
從META-INF/spring-autoconfigure-metadata.properties中加載自動裝配的條件元數據,簡單來說就是只有滿足條件的Bean才能夠進行裝配。
· 收集所有符合條件的配置類
autoConfigurationEntry.getConfigurations(),完成自動裝配。
該類的其他方法:
· getAttributes獲得@EnableAutoConfiguration注解中的屬性exclude、excludeName等。 ·
getCandidateConfigurations獲得所有自動裝配的配置類
· removeDuplicates去除重復的配置項。
· getExclusions根據@EnableAutoConfiguration注解中配置的exclude等屬性,把不需要自動裝配的配置類移除。 ·
fireAutoConfigurationImportEvents廣播事件。
· 最后返回經過多層判斷和過濾之后的配置類集合。
總的來說,它先獲得所有的配置類,通過去重、exclude排除等操作,得到最終需要實現自動裝配的配置類。這里需要重點關注的是getCandidateConfigurations,它是獲得配置類最核心的方法。 這里用到了SpringFactoriesLoader,它是Spring內部提供的一種約定俗成的加載方式,類似于Java中的SPI。簡單來說,它會掃描classpath下的META-INF/spring.factories文件,spring.factories文件中的數據以Key=Value形式存儲,而SpringFactoriesLoader.loadFactoryNames會根據Key得到對應的value值。因此,在這個場景中,Key對應為EnableAutoConfiguration,Value是多個配置類,也就是getCandidateConfigurations方法所返回的值。
總結
????@EnableAutoConfiguraion上有一個@import注解,@Import注解中導入的并不是一個Configuration的配置類,而是一個AutoConfigurationImportSelector類,AutoConfigurationImportSelectori 實現了DeferredImportSelector, DeferredImportSelector繼承了importSelector接口,實現了importSelector接口 重寫了selectImports的類可以批量裝載bean到ioc容器中
????· 通過Spring提供的SpringFactoriesLoader機制,掃描classpath路徑下的META-INF/spring.factories,讀取需要實現自動裝配的配置類。 ·
????通過條件篩選的方式,把不符合條件的配置類移除,最終完成自動裝配。 (@Conditional條件裝配)
總結
以上是生活随笔為你收集整理的【学习笔记】springboot的AutoConfigurationImportSelector 、@EnableAutoConfiguraion和@import解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springboot中使用lua脚本+a
- 下一篇: springboot使用shiro配置多