在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中的?
在之前的文章“容器启动原理揭秘”中提到过,最终通过 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又是什么东西?
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> cache = new ConcurrentReferenceHashMap();
public static List loadFactories(Class factoryClass, @Nullable ClassLoader classLoader) {
Assert.notNull(factoryClass, "'factoryClass' must not be null");
ClassLoader classLoaderToUse = classLoader;
if (classLoader == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
List factoryNames = loadFactoryNames(factoryClass, classLoaderToUse);
if (logger.isTraceEnabled()) {
logger.trace("Loaded [" + factoryClass.getName() + "] names: " + factoryNames);
}
List 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;
}
}
ApplicationListener 就是Spring的事件监听器,最重要的方法就是 onApplicationEvent,而事件源就是spring的广播组件(SimpleApplicationEventMulticaster),所有监听器通过 SpringFactoriesLoader 获取。
//事件监听器
@FunctionalInterface
public interface ApplicationListener 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 {
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的设计功底。
ApplicationContextInitializer 是 ConfigurableApplicationContext(继承自ApplicationContext) 实例后的上下文初始化组件,它主要可以向 applicationContext 注入一些新的bean、修改 applicationContext 基本信息等,核心方法是 initialize,所有实现类通过 SpringFactoriesLoader 获取。
public interface ApplicationContextInitializer {
void initialize(C var1);
}
spring提供的实现非常多,比如:ContextIdApplicationContextInitializer,它实现applicationContext.setId(contextId.getId())。
其实 SpringApplication.run 整体还不算特别复杂,关键的方法有 prepareContext ,refreshContext会比较绕。当然这里面有一个出现的频率非常高的对象 SpringApplicationRunListeners (读源码就是这样,要解决痛点),那它是干什么的?继续向下看吧!
public class SpringApplication {
//真正的入口
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection 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
到这里你感觉是结束了!
但这好像并没看到spring是如何处理 SpringBootApplication、EnableAutoConfiguration 相关的逻辑啊?
如果你真正调试,你会发现一个这样现象:
是的,这发现很重要!!至少知道 refreshContext (就是 AbstractApplicationContext.refresh)是突破口!!
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));
}
}
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有什么区别及联系?
ConfigurationClassPostProcessor(其实是个BeanDefinitionRegistryPostProcessor,之前的文章讲过)今天的主角,处理spring-boot中的SpringBootApplication ,
//AbstractApplicationContext.invokeBeanFactoryPostProcessors的入口
final class PostProcessorRegistrationDelegate {
//里面处理很复杂,但英文注释已经足够了解很多的情况了
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set processedBeans = new HashSet<>();
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List regularPostProcessors = new ArrayList<>();
List 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 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 priorityOrderedPostProcessors = new ArrayList<>();
List orderedPostProcessorNames = new ArrayList<>();
List 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 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 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();
}
}
前面讲过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 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 candidates = new LinkedHashSet<>(configCandidates);
Set alreadyParsed = new HashSet<>(configCandidates.size());
do {
parser.parse(candidates);
parser.validate();
...
}
}
那新的问题来了:
在上面我们讲过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 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 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;
}
}
ConfigurationClassParser是spring boot真正的配置类解析器,当然入口方法是parse。
class ConfigurationClassParser {
public void parse(Set 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 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 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 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 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 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又是什么呢?
个人感觉@EnableAutoConfiguration这个Annotation最为重要,所以放在最后来解读,大家是否还记得Spring框架提供的各种名字为@Enable开头的Annotation定义?比如@EnableScheduling、@EnableCaching、@EnableMBeanExport等,@EnableAutoConfiguration的理念和做事方式其实一脉相承、
简单概括一下就是,借助@Import的支持,收集和注册特定场景相关的bean定义。
而@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
AutoConfigurationPackage它其实是注册了一个Bean的定义。new PackageImport(metadata).getPackageName(),它其实返回了当前主程序类的同级以及子级 的包组件。这也就是为什么,我们要把WebApp放在项目的最高级中。
之前讲过ImportSelector被ConfigurationClassParser调用,AutoConfigurationImportSelector 继承了 DeferredImportSelector 继承了 ImportSelector,有一个重要的方法为:selectImports。就像一只“八爪鱼”一样,勾起spring-boot的强大配置库。
总结,SpringBootApplication注解是通过一个BeanDefinitionRegistryPostProcessor实现解析,在createApplicationContext()时被实例化并注入到Ioc中,在AbstractApplicationContext.refresh被调用PostProcessor。