Springboot自動(dòng)裝配
springboot啟動(dòng)時(shí)我們常見的就是一個(gè)注解@SpringBootApplication 和 SpringApplication的run方法笨鸡,前面介紹過run(http://www.reibang.com/p/90ebeec86f64),今天詳細(xì)看一下@SpringBootApplication匀借。
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
@SpringBootApplication是一個(gè)注解的組合恤磷,進(jìn)去看下它里面
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
主要包含@SpringBootConfiguration狮鸭,@EnableAutoConfiguration浆竭,@ComponentScan
首先@ComponentScan,默認(rèn)掃描的是與該類同級(jí)的類或者同級(jí)包下的所有類
其次@SpringBootConfiguration性昭,只是封裝了@Configuration,把啟動(dòng)類指定為一個(gè)javaConfig(會(huì)在容器刷新中的invokeBeanFactoryPostProcessors里進(jìn)行解析執(zhí)行)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
最后@EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[] excludeName() default {};
}
@EnableAutoConfiguration里面有兩個(gè)主要的注解@AutoConfigurationPackage和@Import(AutoConfigurationImportSelector.class)捎琐。
@AutoConfigurationPackage蓄髓,該注解的作用是添加該注解的類所在的package(啟動(dòng)類所在路徑) 作為 自動(dòng)配置package 進(jìn)行管理叉庐。
@Import(AutoConfigurationImportSelector.class),看一下后面它注冊到容器中的bean AutoConfigurationImportSelector.class会喝。
public class AutoConfigurationImportSelector
implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
BeanFactoryAware, EnvironmentAware, Ordered {
//省略陡叠。。肢执。枉阵。。
其中DeferredImportSelector extends ImportSelector预茄,所以會(huì)執(zhí)行到selectImports岭妖,DeferredImportSelector 和 ImportSelector的區(qū)別在于DeferredImportSelector為延時(shí)加載,等configure都加載完了才開始加載
看一下AutoConfigurationImportSelector里的selectImports
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//判斷是否需要自動(dòng)裝配
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
//從META-INF/spring-autoconfigure-metadata.properties讀取元數(shù)據(jù)與元數(shù)據(jù)的相關(guān)屬性
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//讀取META-INF/spring.factories下的EnableAutoConfiguration的配置(這里用到了SpringFactoriesLoader反璃,和啟動(dòng)過程中加載spring.factories中的初始化器和監(jiān)聽器是同一個(gè))
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
//排除與過濾
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
//讓所有配置在META-INF/spring.factories下的AutoConfigurationImportListener執(zhí)行AutoConfigurationImportEvent事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}
上面這些過程只是確定了需要自定裝配的類昵慌,真正開始處理是在容器刷新中的invokeBeanFactoryPostProcessors方法里,里面用了ConfigurationClassPostProcessor這個(gè)后置處理來處理并且用相應(yīng)的解析器來解析@Configuration注解修飾的類(@Component淮蜈、@ComponentScan斋攀、@Import、@ImportResource修飾的類也會(huì)被處理)梧田,具體可參考http://www.reibang.com/p/ab0b7df24c01
另外淳蔼,每個(gè)需要自動(dòng)裝配的類都可以根據(jù)條件判斷是否進(jìn)行裝配@ConditionalXXX,舉例mq
@Configuration
@ConditionalOnClass({ RabbitTemplate.class, Channel.class })
@EnableConfigurationProperties(RabbitProperties.class)
@Import(RabbitAnnotationDrivenConfiguration.class)
public class RabbitAutoConfiguration {