在spring boot中@SpringBootApplication、@EnableAutoConfiguration是最常見Annotation,且最為重要,是以本文将展開對此的解讀。@SpringBootApplication在spring架構中的處理尤為複雜,然後能将它的來龍去脈(加載機制)講清楚的文章非常少。說實話你要完全了解及解讀它,需要對spring 3.x的源碼有一定程度了解,主要是它在原有的基礎上拓展了一些新概念,如若不按本文的思路,稍有不慎就會陷入代碼的海洋裡不能自拔。
目錄
1. SpringApplication
1.1 SpringFactoriesLoader
1.2 ApplicationListener
1.3 ApplicationContextInitializer
1.4 SpringApplication.run
1.5 SpringApplicationRunListeners和SpringApplicationRunListener
2. AbstractApplicationContext.refresh
2.1 BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor和BeanPostProcessor
2.2 ConfigurationClassPostProcessor
2.4 AnnotationConfigServletWebServerApplicationContext
2.5 ConfigurationClassParser
3. EnableAutoConfiguration
3.1 ImportSelector
@SpringBootApplication(scanBasePackages = {"com.example"})
public class WebApp {
public static void main(String[] args) {
SpringApplication.run(WebApp.class, args);
}
}
首問:@SpringBootApplication是如何被解析并加載到spring ioc中的?
1. SpringApplication
在之前的文章“容器啟動原理揭秘”中提到過,最終通過 JarLauncher.launch 運作的目标是 WebApp.main 方法,之後就沒有再深入的講。首先進入視野的攔路虎就是SpringApplication,可以了解為它相當于spring的外觀模式,集各功能于一身,它也給使用者提供了鍊式文法支援-Builder模式(SpringApplicationBuilder().sources(Parent.class).child(Application.class)..run(args))。
public class SpringApplication {
//入口
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
public SpringApplication(Class... primarySources) {
this((ResourceLoader)null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
this.sources = new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = new HashSet();
this.isCustomEnvironment = false;
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
// 判斷web類型為reactive、none、servlet(隻要可以加載Servlet或ConfigurableWebApplicationContext),目前為servlet
this.webApplicationType = this.deduceWebApplicationType();
//從SpringFactoriesLoader中加載ApplicationContextInitializer類,并執行個體化
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
//從SpringFactoriesLoader中加載ApplicationListener類,并執行個體化
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
//這個是很重要的屬性:WebApp
this.mainApplicationClass = this.deduceMainApplicationClass();
}
}
你可能會問:SpringFactoriesLoader是什麼鬼?ApplicationContextInitializer和ApplicationListener又是什麼東西?
1.1 SpringFactoriesLoader
SpringFactoriesLoader 在spring boot中非常重要,它是spring對SPI的實作版本,主要是從jar中META-INF/spring.factories讀取拓展配置資訊。在spring boot架構中有兩個核心的 jar,它内置的 spring.factories 非常重要(使用者一般很少關注),而一般功能進行拓展也基于此:
spring-boot-2.0.5.RELEASE.jar/META-INF/spring.factories
# PropertySource Loaders org.springframework.boot.env.PropertySourceLoader=\ org.springframework.boot.env.PropertiesPropertySourceLoader,\ org.springframework.boot.env.YamlPropertySourceLoader # Run Listeners org.springframework.boot.SpringApplicationRunListener=\ org.springframework.boot.context.event.EventPublishingRunListener # Error Reporters org.springframework.boot.SpringBootExceptionReporter=\ org.springframework.boot.diagnostics.FailureAnalyzers # Application Context Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\ org.springframework.boot.context.ContextIdApplicationContextInitializer,\ org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\ org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer # Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.ClearCachesApplicationListener,\ org.springframework.boot.builder.ParentContextCloserApplicationListener,\ org.springframework.boot.context.FileEncodingApplicationListener,\ org.springframework.boot.context.config.AnsiOutputApplicationListener,\
spring-boot-autoconfigure-2.0.5.RELEASE.jar/META-INF/spring.factories
# Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\ org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener # Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.autoconfigure.BackgroundPreinitializer # Auto Configuration Import Listeners org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\ org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener # Auto Configuration Import Filters org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\ org.springframework.boot.autoconfigure.condition.OnClassCondition # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
SpringFactoriesLoader 源碼其實也不複雜,這裡不再贅述。
public abstract class SpringFactoriesLoader {
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap();
public static <T> List<T> loadFactories(Class<T> factoryClass, @Nullable ClassLoader classLoader) {
Assert.notNull(factoryClass, "'factoryClass' must not be null");
ClassLoader classLoaderToUse = classLoader;
if (classLoader == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
List<String> factoryNames = loadFactoryNames(factoryClass, classLoaderToUse);
if (logger.isTraceEnabled()) {
logger.trace("Loaded [" + factoryClass.getName() + "] names: " + factoryNames);
}
List<T> result = new ArrayList(factoryNames.size());
Iterator var5 = factoryNames.iterator();
while(var5.hasNext()) {
String factoryName = (String)var5.next();
result.add(instantiateFactory(factoryName, factoryClass, classLoaderToUse));
}
AnnotationAwareOrderComparator.sort(result);
return result;
}
}
1.2 ApplicationListener
ApplicationListener 就是Spring的事件監聽器,最重要的方法就是 onApplicationEvent,而事件源就是spring的廣播元件(SimpleApplicationEventMulticaster),所有監聽器通過 SpringFactoriesLoader 擷取。
//事件監聽器
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
void onApplicationEvent(E var1);
}
//廣播事件
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
public void multicastEvent(ApplicationEvent event) {
this.multicastEvent(event, this.resolveDefaultEventType(event));
}
//添加監聽器
public void addApplicationListener(ApplicationListener<?> listener) {
Object var2 = this.retrievalMutex;
synchronized(this.retrievalMutex) {
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
if (singletonTarget instanceof ApplicationListener) {
this.defaultRetriever.applicationListeners.remove(singletonTarget);
}
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
}
//較重要的監聽器實作類
public class BackgroundPreinitializer implements ApplicationListener<SpringApplicationEvent> {
public void onApplicationEvent(SpringApplicationEvent event) {
//如果是首次觸發ApplicationStartingEvent時執行
if (event instanceof ApplicationStartingEvent && preinitializationStarted.compareAndSet(false, true)) {
this.performPreinitialization();
}
if ((event instanceof ApplicationReadyEvent || event instanceof ApplicationFailedEvent) && preinitializationStarted.get()) {
try {
preinitializationComplete.await();
} catch (InterruptedException var3) {
Thread.currentThread().interrupt();
}
}
}
private void performPreinitialization() {
try {
Thread thread = new Thread(new Runnable() {
public void run() {
this.runSafely(new BackgroundPreinitializer.ConversionServiceInitializer());
this.runSafely(new BackgroundPreinitializer.ValidationInitializer());
this.runSafely(new BackgroundPreinitializer.MessageConverterInitializer());
this.runSafely(new BackgroundPreinitializer.MBeanFactoryInitializer());
this.runSafely(new BackgroundPreinitializer.JacksonInitializer());
this.runSafely(new BackgroundPreinitializer.CharsetInitializer());
BackgroundPreinitializer.preinitializationComplete.countDown();
}
public void runSafely(Runnable runnable) {
try {
runnable.run();
} catch (Throwable var3) {
;
}
}
}, "background-preinit");
thread.start();
} catch (Exception var2) {
preinitializationComplete.countDown();
}
}
}
題外話,BackgroundPreinitializer 把耗時的操作采用這種模式(事件+多線程)來實作,足以可見spring的設計功底。
1.3 ApplicationContextInitializer
ApplicationContextInitializer 是 ConfigurableApplicationContext(繼承自ApplicationContext) 執行個體後的上下文初始化元件,它主要可以向 applicationContext 注入一些新的bean、修改 applicationContext 基本資訊等,核心方法是 initialize,所有實作類通過 SpringFactoriesLoader 擷取。
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
void initialize(C var1);
}
spring提供的實作非常多,比如:ContextIdApplicationContextInitializer,它實作applicationContext.setId(contextId.getId())。
1.4 SpringApplication.run
其實 SpringApplication.run 整體還不算特别複雜,關鍵的方法有 prepareContext ,refreshContext會比較繞。當然這裡面有一個出現的頻率非常高的對象 SpringApplicationRunListeners (讀源碼就是這樣,要解決痛點),那它是幹什麼的?繼續向下看吧!
public class SpringApplication {
//真正的入口
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
//下面專門解釋
SpringApplicationRunListeners listeners = this.getRunListeners(args);
//觸發ApplicationStartingEvent
listeners.starting();
Collection exceptionReporters;
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//擷取配置對象
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
//向environment添加新配置
this.configureIgnoreBeanInfo(environment);
//列印spring boot的Banner
Banner printedBanner = this.printBanner(environment);
//根據webApplicationType類型擷取applicationContext,目前為AnnotationConfigServletWebServerApplicationContext
context = this.createApplicationContext();
//異常彙總報告
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
//向applicationContext中填充資訊(environment、調用ApplicationContextInitializer、注入新bean)
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//重新整理application
this.refreshContext(context);
//無任何實作
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
//列印日志
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
//觸發ApplicationStartedEvent
listeners.started(context);
//調用ioc中所有ApplicationRunner.run和CommandLineRunner.run
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
//觸發ApplicationReadyEvent
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
//觸發ApplicationEnvironmentPreparedEvent
listeners.environmentPrepared((ConfigurableEnvironment)environment);
this.bindToSpringApplication((ConfigurableEnvironment)environment);
if (!this.isCustomEnvironment) {
//根據webApplicationType類型擷取配置對象(環境資訊、profile),目前為StandardServletEnvironment
environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
}
ConfigurationPropertySources.attach((Environment)environment);
return (ConfigurableEnvironment)environment;
}
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
//注入beanNameGenerator、設定ResourceLoader
this.postProcessApplicationContext(context);
//調用所有的初始化元件(ApplicationContextInitializer)
this.applyInitializers(context);
//無任何實作
listeners.contextPrepared(context);
if (this.logStartupInfo) {
//列印getApplicationLog()資訊
this.logStartupInfo(context.getParent() == null);
// 列印Profile資訊
this.logStartupProfileInfo(context);
}
//ioc容器儲存應用程式啟動參數(String[] args)資訊
context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
//ioc容器儲存Banner資訊
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
Set<Object> sources = this.getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
//把啟動類(WebApp )注入到Ioc容器中,調用BeanDefinitionLoader.load
this.load(context, sources.toArray(new Object[0]));
//觸發ApplicationPreparedEvent
listeners.contextLoaded(context);
}
private void refreshContext(ConfigurableApplicationContext context) {
//調用AbstractApplicationContext.refresh(後面專門講)
this.refresh(context);
//添加鈎子函數
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
} catch (AccessControlException var3) {
;
}
}
}
}
class BeanDefinitionLoader {
//prepareContext方法中this.load最終會執行到這裡
private int load(Class<?> source) {
if (this.isGroovyPresent() && BeanDefinitionLoader.GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
BeanDefinitionLoader.GroovyBeanDefinitionSource loader = (BeanDefinitionLoader.GroovyBeanDefinitionSource)BeanUtils.instantiateClass(source, BeanDefinitionLoader.GroovyBeanDefinitionSource.class);
this.load(loader);
}
//WebApp類符合條件
if (this.isComponent(source)) {
this.annotatedReader.register(new Class[]{source});
return 1;
} else {
return 0;
}
}
}
到這裡你感覺是結束了!
但這好像并沒看到spring是如何處理 SpringBootApplication、EnableAutoConfiguration 相關的邏輯啊?
如果你真正調試,你會發現一個這樣現象:
- 未執行refreshContext方法前,applicationContext (Ioc容器)好像注入的的bean非常少,其中一個就是WebApp對象
- 執行refreshContext之後,applicationContext (Ioc容器)裡什麼都有了,的确是 SpringBootApplication、EnableAutoConfiguration 生效了
是的,這發現很重要!!至少知道 refreshContext (就是 AbstractApplicationContext.refresh)是突破口!!
1.5 SpringApplicationRunListeners和SpringApplicationRunListener
SpringApplicationRunListeners 管理着 applicationContext 初始化、執行個體化、啟動運作的各個階段,它最重要的職責就是通過事件驅動與外界的聯系。SpringApplicationRunListener是通過 SpringFactoriesLoader 擷取的,它定義了applicationContext 的各個階段及其實作(EventPublishingRunListener ),EventPublishingRunListener的特點是事件驅動,它通過事件廣播元件SimpleApplicationEventMulticaster與外界交換。
class SpringApplicationRunListeners {
SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
this.log = log;
//通過SpringApplicationRunListener
this.listeners = new ArrayList(listeners);
}
public void starting() {
Iterator var1 = this.listeners.iterator();
//調用所有的SpringApplicationRunListener.starting
while(var1.hasNext()) {
SpringApplicationRunListener listener = (SpringApplicationRunListener)var1.next();
listener.starting();
}
}
public void started(ConfigurableApplicationContext context) {
Iterator var2 = this.listeners.iterator();
while(var2.hasNext()) {
SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next();
listener.started(context);
}
}
}
//SpringApplicationRunListener是通過SpringFactoriesLoader擷取的
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
//applicationContext的各個階段
public interface SpringApplicationRunListener {
void starting();//啟動中
void environmentPrepared(ConfigurableEnvironment environment);//環境變量初始化
void contextPrepared(ConfigurableApplicationContext context);//上下文準備
void contextLoaded(ConfigurableApplicationContext context);
void started(ConfigurableApplicationContext context);
void running(ConfigurableApplicationContext context);
void failed(ConfigurableApplicationContext context, Throwable exception);//失敗
}
//支援事件驅動的SpringApplicationRunListener的實作
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
//事件廣播元件
this.initialMulticaster = new SimpleApplicationEventMulticaster();
Iterator var3 = application.getListeners().iterator();
while(var3.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var3.next();
this.initialMulticaster.addApplicationListener(listener);
}
}
public void starting() {
//發事件
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
}
public void contextLoaded(ConfigurableApplicationContext context) {
ApplicationListener listener;
for(Iterator var2 = this.application.getListeners().iterator(); var2.hasNext(); context.addApplicationListener(listener)) {
listener = (ApplicationListener)var2.next();
if (listener instanceof ApplicationContextAware) {
((ApplicationContextAware)listener).setApplicationContext(context);
}
}
//發事件
this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}
public void started(ConfigurableApplicationContext context) {
//發事件
context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
}
}
2. AbstractApplicationContext.refresh
AbstractApplicationContext.refresh 是非常複雜的,為避免知識點無限延伸,和本文主題相關性不大的東西不展開探讨。
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
public void refresh() throws BeansException, IllegalStateException {
Object var1 = this.startupShutdownMonitor;
synchronized(this.startupShutdownMonitor) {
//設定this.startupDate、this.closed=true,this.active=true,initPropertySources()、validateRequiredProperties()
this.prepareRefresh();
/**通知子類重新整理内部的bean factory,主要分為兩步:
* refreshBeanFactory(進行真正的配置加載,xml是在這一步解析的,讀取注冊的regular bean)
* 擷取beanFactory
*/
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
/**配置beanFactory标準的上下文特性,非常複雜
* set:classLoader
* set:StandardBeanExpressionResolver (spring EL)
* addBeanPostProcessor:ApplicationContextAwareProcessor(BeanPostProcessor提供set各種aware)
* addBeanPostProcessor:ApplicationListenerDetector(ApplicationListener處理)
* ignoreDependencyInterface、registerResolvableDependency
*/
this.prepareBeanFactory(beanFactory);
try {
//在子類中,允許對beanFactory進行後期處理
this.postProcessBeanFactory(beanFactory);
//執行BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor,後面專門講
this.invokeBeanFactoryPostProcessors(beanFactory);
/**添加執行個體化的後置處理器,并對所有的進行排序
* BeanPostProcessorChecker
* ApplicationListenerDetector
**/
this.registerBeanPostProcessors(beanFactory);
//初始化國際化服務
this.initMessageSource();
//建立事件廣播器
this.initApplicationEventMulticaster();
//在子類中實作
this.onRefresh();
/**注冊一部分給出的事件監聽器,
* addApplicationListenerBean:隻添加監聽器的名字(留待bean執行個體化完成後再注冊)
**/
this.registerListeners();
//單例模式的bean的執行個體化、成員變量注入、初始化等工作都在此完成
this.finishBeanFactoryInitialization(beanFactory);
/**applicationContext重新整理完成後的處理
* initLifecycleProcessor()
* this.getLifecycleProcessor().onRefresh
* this.publishEvent(new ContextRefreshedEvent(this));
**/
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
//重新整理失敗後的處理,主要是将一些儲存環境資訊的集合做清理
this.destroyBeans();
//applicationContext是否已經激活的标志,設定為false
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
}
這裡有一點基本上可以确認了:refresh調用方法invokeBeanFactoryPostProcessors(beanFactory)
其實這裡有一個疑問:regular bean是什麼?BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor有什麼差別及聯系?
2.1 BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor和BeanPostProcessor
ConfigurationClassPostProcessor(其實是個BeanDefinitionRegistryPostProcessor,之前的文章講過)今天的主角,處理spring-boot中的SpringBootApplication ,
//AbstractApplicationContext.invokeBeanFactoryPostProcessors的入口
final class PostProcessorRegistrationDelegate {
//裡面處理很複雜,但英文注釋已經足夠了解很多的情況了
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>();
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
// Invoke factory processors registered with the context instance.
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// Finally, invoke all other BeanFactoryPostProcessors.
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
beanFactory.clearMetadataCache();
}
}
2.2 ConfigurationClassPostProcessor
前面講過ConfigurationClassPostProcessor實是個BeanDefinitionRegistryPostProcessor。還是看源碼吧,其實不需要所有的地方都懂,有注釋的地方看懂就能了解今天的真相。
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
if (this.factoriesPostProcessed.contains(factoryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + beanFactory);
}
this.factoriesPostProcessed.add(factoryId);
if (!this.registriesPostProcessed.contains(factoryId)) {
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
//看這裡啊,英文解釋很明确,處理Configuration類
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
enhanceConfigurationClasses(beanFactory);
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
//從ioc中找到有spring注解的bean
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// Return immediately if no @Configuration classes were found
if (configCandidates.isEmpty()) {
return;
}
...
// Parse each @Configuration class
// ConfigurationClassParser 後面具體講
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
parser.parse(candidates);
parser.validate();
...
}
}
那新的問題來了:
- ConfigurationClassPostProcessor是什麼時候注入到spring ioc中的呢?
- ConfigurationClassParser又是什麼呢?
2.4 AnnotationConfigServletWebServerApplicationContext
在上面我們講過SpringApplication.createApplicationContext(),最終得到的是AnnotationConfigServletWebServerApplicationContext,看源碼吧
public class AnnotationConfigServletWebServerApplicationContext extends ServletWebServerApplicationContext implements AnnotationConfigRegistry {
public AnnotationConfigServletWebServerApplicationContext() {
this.annotatedClasses = new LinkedHashSet();
//reader 這個對象很關鍵
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
}
public class AnnotatedBeanDefinitionReader {
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
this(registry, getOrCreateEnvironment(registry));
}
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);
//它注入了一些BeanFactoryPostProcessor
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
}
public class AnnotationConfigUtils {
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable 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<>(8);
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
//看這裡,就是spring boot注解處理類
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)) {
//Autowired注解處理類
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)) {
//Required注解處理類
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;
}
}
2.5 ConfigurationClassParser
ConfigurationClassParser是spring boot真正的配置類解析器,當然入口方法是parse。
class ConfigurationClassParser {
public void parse(Set<BeanDefinitionHolder> configCandidates) {
this.deferredImportSelectors = new LinkedList<>();
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
processDeferredImportSelectors();
}
//ImportSelector後續專門講
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
//對ImportSelector的處理
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
//執行個體化selector
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
//
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
//如果為延遲導入處理則加入集合當中
this.deferredImportSelectors.add(
new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
}
else {
//根據ImportSelector方法的傳回值來進行遞歸操作
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// 如果目前的類既不是ImportSelector也不是ImportBeanDefinitionRegistar就進行@Configuration的解析處理
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}
//處理spring各種注解類
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
// Process any @PropertySource annotations
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// Process any @ComponentScan annotations
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true);
// Process any @ImportResource annotations
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// Process individual @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
processInterfaces(configClass, sourceClass);
// Process superclass, if any
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
// No superclass -> processing is complete
return null;
}
}
那最剩下最後一個問題:ImportSelector又是什麼呢?
3. EnableAutoConfiguration
個人感覺@EnableAutoConfiguration這個Annotation最為重要,是以放在最後來解讀,大家是否還記得Spring架構提供的各種名字為@Enable開頭的Annotation定義?比如@EnableScheduling、@EnableCaching、@EnableMBeanExport等,@EnableAutoConfiguration的理念和做事方式其實一脈相承、
簡單概括一下就是,借助@Import的支援,收集和注冊特定場景相關的bean定義。
- @EnableScheduling是通過@Import将Spring排程架構相關的bean定義都加載到IoC容器。
- @EnableMBeanExport是通過@Import将JMX相關的bean定義加載到IoC容器。
而@EnableAutoConfiguration也是借助@Import的幫助,将所有符合自動配置條件的bean定義加載到IoC容器,僅此而已!
@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 {};
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
}
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
}
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
}
}
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.filter(configurations, autoConfigurationMetadata);
//觸發AutoConfigurationImportEvent
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}
}
//從spring.factories中EnableAutoConfiguration擷取所有
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
}
AutoConfigurationPackage它其實是注冊了一個Bean的定義。new PackageImport(metadata).getPackageName(),它其實傳回了目前主程式類的同級以及子級 的包元件。這也就是為什麼,我們要把WebApp放在項目的最進階中。
3.1 ImportSelector
之前講過ImportSelector被ConfigurationClassParser調用,AutoConfigurationImportSelector 繼承了 DeferredImportSelector 繼承了 ImportSelector,有一個重要的方法為:selectImports。就像一隻“八爪魚”一樣,勾起spring-boot的強大配置庫。
總結,SpringBootApplication注解是通過一個BeanDefinitionRegistryPostProcessor實作解析,在createApplicationContext()時被執行個體化并注入到Ioc中,在AbstractApplicationContext.refresh被調用PostProcessor。