Spring Boot自動配置註解@EnableAutoConfiguration解密
Spring boot為了自動配置,增加了註解@EnableAutoConfiguration。一般只需要配置@SpringBootApplication即可,為什麼呢?
@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
的組合。
@SpringBootConfiguration
這個註解實際上和@Configuration
有相同的作用,配備了該註解的類就能夠以JavaConfig的方式完成一些配置,可以不再使用XML配置。
@ComponentScan
<context:component-scan>
,可以使用basePackages屬性指定要掃描的包,以及掃描的條件。如果不設定的話預設掃描@ComponentScan
註解所在類的同級類和同級目錄下的所有類,所以對於一個Spring Boot專案,一般會把入口類放在頂層目錄中,這樣就能夠保證原始碼目錄下的所有類都能夠被掃描到。 @EnableAutoConfiguration
註解程式碼如下:
@SuppressWarnings("deprecation")
@Target(ElementType.TYPE)
@Retention (RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
這個註解是讓Spring Boot的配置能夠如此簡化的關鍵性註解。尤其是@Import
註解中的那個EnableAutoConfigurationImportSelector.class
。那麼這個註解到底是怎麼生效的呢?
在SpringApplication的run方法中,會調context = createApplicationContext();
在例項化這個ConfigurableApplicationContext
時,不管是AnnotationConfigEmbeddedWebApplicationContext
或AnnotationConfigApplicationContext
時(這兩個類是專門處理Spring註解方式配置的容器,直接依賴於註解作為容器配置資訊來源的IoC容器。 AnnotationConfigWebApplicationContext
是AnnotationConfigApplicationContext
的web版本,兩者的用法以及對註解的處理方式幾乎沒有什麼差別),都會例項化一個AnnotatedBeanDefinitionReader
。例如AnnotationConfigEmbeddedWebApplicationContext
例項化程式碼:
public AnnotationConfigEmbeddedWebApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
這裡將構造AnnotatedBeanDefinitionReader
,在AnnotatedBeanDefinitionReader
例項化過程中,會向beanFactory註冊CommonAnnotationBeanPostProcessor
、AutowiredAnnotationBeanPostProcessor
、ConfigurationClassPostProcessor
等:
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, Object source) {
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
}
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
}
return beanDefs;
}
也就是說createApplicationContext()
完後,beanFactory的beanDefinitionMap
會有6個值。
SpringApplication的run方法中,在呼叫createApplicationContext();
後會呼叫prepareContext(context, environment, listeners, applicationArguments,printedBanner)
:
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
// ….
// Load the sources
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));
listeners.contextLoaded(context);
}
getSources()
返回的就是new SpringApplication(Application.class)
傳入的引數,即我們的主類,然後呼叫了load()
方法,在load()
中會生成BeanDefinitionLoader
例項,並把主類註冊到IOC容器中。
OK,到這裡即在呼叫我們熟悉的AbstractApplicationContext#refresh()
前,beanFactory有7個定義好的beanDefinition。
ConfigurationClassPostProcessor
是BeanFactoryPostProcessor
的子類,會在Spring容器refresh時,invokeBeanFactoryPostProcessors(beanFactory)
方法中呼叫到。ConfigurationClassPostProcessor
會解析到我們的主類,把@Import
中的類拿出來,呼叫它的selectImports()
方法。
selectImports
方法在EnableAutoConfigurationImportSelector
的父類AutoConfigurationImportSelector
類中:
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
try {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
configurations = removeDuplicates(configurations);
configurations = sort(configurations, autoConfigurationMetadata);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return configurations.toArray(new String[configurations.size()]);
}
catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
getCandidateConfigurations
方法就會在META-INF/spring.factories
中找到獲取約定好的自動配置類(key為EnableAutoConfiguration的value)。然後Spring容器會對這些配置類進行處理。
到此,一目瞭然,由ConfigurationClassPostProcessor
來處理。@ComponentScan
註解也是在ConfigurationClassPostProcessor
中處理的。