一、源碼分析
首先是項目啟動類
public static void main(String[] args) {
SpringApplication.run(MarsApplication.class, args);
}
初始化時,會加載META-INF/spring.factories文件,來看一下deduceWebEnvironment()方法
private WebApplicationType deduceWebApplicationType() {
if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
&& !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : WEB_ENVIRONMENT_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
這里主要是通過判斷REACTIVE相關(guān)的字節(jié)碼是否存在,如果不存在,則web環(huán)境即為SERVLET類型。這里設(shè)置好web環(huán)境類型,在后面會根據(jù)類型初始化對應(yīng)環(huán)境。ApplicationContextInitializer是spring組件spring-context組件中的一個接口,主要是spring ioc容器刷新之前的一個回調(diào)接口,用于處于自定義邏輯。spring.factories文件中的實現(xiàn)類:
# 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,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
還有1個為:org.springframework.boot.autoconfigure.BackgroundPreinitializer這10個監(jiān)聽器會貫穿SpringBoot整個生命周期。
來看一下run方法:
public ConfigurableApplicationContext run(String... args) {
//時間監(jiān)控
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
//java.awt.headless是J2SE的一種模式用于在缺少顯示屏、鍵盤或者鼠標(biāo)時的系統(tǒng)配置,很多監(jiān)控工具如jconsole 需要將該值設(shè)置為true,系統(tǒng)變量默認(rèn)為true
configureHeadlessProperty();
//獲取spring.factories中的監(jiān)聽器變量,args為指定的參數(shù)數(shù)組,默認(rèn)為當(dāng)前類SpringApplication
//第一步:獲取并啟動監(jiān)聽器
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//第二步:構(gòu)造容器環(huán)境
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
//設(shè)置需要忽略的bean
configureIgnoreBeanInfo(environment);
//打印banner
Banner printedBanner = printBanner(environment);
//第三步:創(chuàng)建容器
context = createApplicationContext();
//第四步:實例化SpringBootExceptionReporter.class,用來支持報告關(guān)于啟動的錯誤
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//第五步:準(zhǔn)備容器
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//第六步:刷新容器
refreshContext(context);
//第七步:刷新容器后的擴(kuò)展接口
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
- 第一步:獲取并啟動監(jiān)聽器
- 第二步:構(gòu)造容器環(huán)境
- 第三步:創(chuàng)建容器
- 第四步:實例化SpringBootExceptionReporter.class,用來支持報告關(guān)于啟動的錯誤
- 第五步:準(zhǔn)備容器
- 第六步:刷新容器
- 第七步:刷新容器后的擴(kuò)展接口
二、步驟分析
2.1 獲取并啟動監(jiān)聽器
2.1.1 獲取監(jiān)聽器
SpringApplicationRunListeners listeners = getRunListeners(args); 跟進(jìn)getRunListeners方法:
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
上面可以看到,args本身默認(rèn)為空,但是在獲取監(jiān)聽器的方法中,getSpringFactoriesInstances( SpringApplicationRunListener.class, types, this, args)將當(dāng)前對象作為參數(shù),該方法用來獲取spring.factories對應(yīng)的監(jiān)聽器:
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
整個SpringBoot 框架中獲取factories的方式統(tǒng)一如下:
@SuppressWarnings("unchecked")
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
Set<String> names) {
List<T> instances = new ArrayList<>(names.size());
for (String name : names) {
try {
//裝載class文件到內(nèi)存
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass
.getDeclaredConstructor(parameterTypes);
//主要通過反射創(chuàng)建實例
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException(
"Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
上面通過反射獲取實例時會觸發(fā)EventPublishingRunListener的構(gòu)造函數(shù):
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
重點來看一下addApplicationListener方法:
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
synchronized (this.retrievalMutex) {
// Explicitly remove target for a proxy, if registered already,
// in order to avoid double invocations of the same listener.
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
if (singletonTarget instanceof ApplicationListener) {
this.defaultRetriever.applicationListeners.remove(singletonTarget);
}
//內(nèi)部類對象
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
上述方法定義在SimpleApplicationEventMulticaster父類AbstractApplicationEventMulticaster中。關(guān)鍵代碼為this.defaultRetriever.applicationListeners.add(listener);,這是一個內(nèi)部類,用來保存所有的監(jiān)聽器。也就是在這一步,將spring.factories中的監(jiān)聽器傳遞到SimpleApplicationEventMulticaster中。
2.1.2 啟動監(jiān)聽器
listeners.starting();,獲取的監(jiān)聽器為EventPublishingRunListener,從名字可以看出是啟動事件發(fā)布監(jiān)聽器,主要用來發(fā)布啟動事件。
@Override
public void starting() {
//關(guān)鍵代碼,這里是創(chuàng)建application啟動事件`ApplicationStartingEvent`
this.initialMulticaster.multicastEvent(
new ApplicationStartingEvent(this.application, this.args));
}
EventPublishingRunListener這個是SpringBoot框架中最早執(zhí)行的監(jiān)聽器,在該監(jiān)聽器執(zhí)行started()方法時,會繼續(xù)發(fā)布事件,也就是事件傳遞。這種實現(xiàn)主要還是基于Spring的事件機(jī)制。繼續(xù)跟進(jìn)SimpleApplicationEventMulticaster,有個核心方法:
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
//獲取線程池,如果為空則同步處理。這里線程池為空,還未沒初始化。
Executor executor = getTaskExecutor();
if (executor != null) {
//異步發(fā)送事件
executor.execute(() -> invokeListener(listener, event));
}
else {
//同步發(fā)送事件
invokeListener(listener, event);
}
}
}
這里會根據(jù)事件類型ApplicationStartingEvent獲取對應(yīng)的監(jiān)聽器,在容器啟動之后執(zhí)行響應(yīng)的動作。
這是SpringBoot啟動過程中,第一處根據(jù)類型,執(zhí)行監(jiān)聽器的地方。根據(jù)發(fā)布的事件類型從上述10種監(jiān)聽器中選擇對應(yīng)的監(jiān)聽器進(jìn)行事件發(fā)布,當(dāng)然如果繼承了 SpringCloud或者別的框架,就不止10個了。這里選了一個 SpringBoot 的日志監(jiān)聽器來進(jìn)行講解,核心代碼如下:
@Override
public void onApplicationEvent(ApplicationEvent event) {
//在springboot啟動的時候
if (event instanceof ApplicationStartedEvent) {
onApplicationStartedEvent((ApplicationStartedEvent) event);
}
//springboot的Environment環(huán)境準(zhǔn)備完成的時候
else if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent(
(ApplicationEnvironmentPreparedEvent) event);
}
//在springboot容器的環(huán)境設(shè)置完成以后
else if (event instanceof ApplicationPreparedEvent) {
onApplicationPreparedEvent((ApplicationPreparedEvent) event);
}
//容器關(guān)閉的時候
else if (event instanceof ContextClosedEvent && ((ContextClosedEvent) event)
.getApplicationContext().getParent() == null) {
onContextClosedEvent();
}
//容器啟動失敗的時候
else if (event instanceof ApplicationFailedEvent) {
onApplicationFailedEvent();
}
}
因為我們的事件類型為ApplicationEvent,所以會執(zhí)行onApplicationStartedEvent((ApplicationStartedEvent) event);。SpringBoot會在運(yùn)行過程中的不同階段,發(fā)送各種事件,來執(zhí)行對應(yīng)監(jiān)聽器的對應(yīng)方法。
2.2 環(huán)境構(gòu)建
ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments); 跟進(jìn)去該方法:
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
//獲取對應(yīng)的ConfigurableEnvironment
ConfigurableEnvironment environment = getOrCreateEnvironment();
//配置
configureEnvironment(environment, applicationArguments.getSourceArgs());
//發(fā)布環(huán)境已準(zhǔn)備事件,這是第二次發(fā)布事件
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
if (this.webApplicationType == WebApplicationType.NONE) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
ConfigurationPropertySources.attach(environment);
return environment;
}
來看一下getOrCreateEnvironment()方法,前面已經(jīng)提到,environment已經(jīng)被設(shè)置了servlet類型,所以這里創(chuàng)建的是環(huán)境對象是StandardServletEnvironment。
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
if (this.webApplicationType == WebApplicationType.SERVLET) {
return new StandardServletEnvironment();
}
return new StandardEnvironment();
}
枚舉類WebApplicationType是SpringBoot2新增的特性,主要針對spring5引入的reactive特性。枚舉類型如下:
public enum WebApplicationType {
//不需要再web容器的環(huán)境下運(yùn)行,普通項目
NONE,
//基于servlet的web項目
SERVLET,
//這個是spring5版本開始的新特性
REACTIVE
}
Environment接口提供了4種實現(xiàn)方式,StandardEnvironment、StandardServletEnvironment和MockEnvironment、StandardReactiveWebEnvironment,分別代表普通程序、Web程序、測試程序的環(huán)境、響應(yīng)式web環(huán)境。
在返回return new StandardServletEnvironment();對象的時候,會完成一系列初始化動作,主要就是將運(yùn)行機(jī)器的系統(tǒng)變量和環(huán)境變量,加入到其父類AbstractEnvironment定義的對象MutablePropertySources中,MutablePropertySources對象中定義了一個屬性集合:
private final List<PropertySource<?>> propertySourceList = new CopyOnWriteArrayList<PropertySource<?>>();
執(zhí)行到這里,系統(tǒng)變量和環(huán)境變量已經(jīng)被載入到配置文件的集合中,接下來就行解析項目中的配置文件。來看一下listeners.environmentPrepared(environment);,上面已經(jīng)提到了,這里是第二次發(fā)布事件。什么事件呢?顧名思義,系統(tǒng)環(huán)境初始化完成的事件。
可以看到獲取到的監(jiān)聽器和第一次發(fā)布啟動事件獲取的監(jiān)聽器有幾個是重復(fù)的,這也驗證了監(jiān)聽器是可以多次獲取,根據(jù)事件類型來區(qū)分具體處理邏輯。上面介紹日志監(jiān)聽器的時候已經(jīng)提到。主要來看一下ConfigFileApplicationListener,該監(jiān)聽器非常核心,主要用來處理項目配置。項目中的 properties 和yml文件都是其內(nèi)部類所加載。
首先還是會去讀spring.factories 文件,List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();獲取的處理類有以下四種:
# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor= //一個@FunctionalInterface函數(shù)式接口
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,//為springCloud提供的擴(kuò)展類
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,//支持json環(huán)境變量
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor //springBoo2提供的一個包裝類,主要將`StandardServletEnvironment`包裝成`SystemEnvironmentPropertySourceEnvironmentPostProcessor`對象
在執(zhí)行完上述三個監(jiān)聽器流程后,ConfigFileApplicationListener會執(zhí)行該類本身的邏輯。由其內(nèi)部類Loader加載項目制定路徑下的配置文件:
private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/";
2.3 創(chuàng)建容器
context = createApplicationContext(); 繼續(xù)跟進(jìn)該方法:
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",
ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
上面可以看出,這里創(chuàng)建容器的類型 還是根據(jù)webApplicationType進(jìn)行判斷的,因為該類型為SERVLET類型,所以會通過反射裝載對應(yīng)的字節(jié)碼,如下:
public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
該對象是SpringBoot2創(chuàng)建的容器,后續(xù)所有的操作都會基于該容器。
2.4 報告錯誤信息
這里還是以同樣的方式獲取spring.factories文件中的指定類:
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
該類主要是在項目啟動失敗之后,打印log:
private void reportFailure(Collection<SpringBootExceptionReporter> exceptionReporters,Throwable failure) {
try {
for (SpringBootExceptionReporter reporter : exceptionReporters) {
if (reporter.reportException(failure)) {
//上報錯誤log
registerLoggedException(failure);
return;
}
}
}
catch (Throwable ex) {
// Continue with normal handling of the original failure
}
if (logger.isErrorEnabled()) {
logger.error("Application run failed", failure);
registerLoggedException(failure);
}
}
2.5 準(zhǔn)備容器
這一步主要是在容器刷新之前的準(zhǔn)備動作。包含一個非常關(guān)鍵的操作:將啟動類注入容器,為后續(xù)開啟自動化配置奠定基礎(chǔ)。
prepareContext(context, environment, listeners, applicationArguments,printedBanner);
繼續(xù)跟進(jìn)該方法:
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
//設(shè)置容器環(huán)境,包括各種變量
context.setEnvironment(environment);
//執(zhí)行容器后置處理
postProcessApplicationContext(context);
//執(zhí)行容器中的ApplicationContextInitializer(包括 spring.factories和自定義的實例)
applyInitializers(context);
//發(fā)送容器已經(jīng)準(zhǔn)備好的事件,通知各監(jiān)聽器
listeners.contextPrepared(context);
//打印log
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
//注冊啟動參數(shù)bean,這里將容器指定的參數(shù)封裝成bean,注入容器
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
//設(shè)置banner
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// Load the sources
//獲取我們的啟動類指定的參數(shù),可以是多個
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
//加載我們的啟動類,將啟動類注入容器
load(context, sources.toArray(new Object[0]));
//發(fā)布容器已加載事件。
listeners.contextLoaded(context);
}
來看一下上面的幾個核心處理
2.5.1 容器的后置處理
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
if (this.beanNameGenerator != null) {
context.getBeanFactory().registerSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
this.beanNameGenerator);
}
if (this.resourceLoader != null) {
if (context instanceof GenericApplicationContext) {
((GenericApplicationContext) context)
.setResourceLoader(this.resourceLoader);
}
if (context instanceof DefaultResourceLoader) {
((DefaultResourceLoader) context)
.setClassLoader(this.resourceLoader.getClassLoader());
}
}
}
這里默認(rèn)不執(zhí)行任何邏輯,因為beanNameGenerator和resourceLoader默認(rèn)為空。之所以這樣做,是SpringBoot留給我們的擴(kuò)展處理方式,類似于這樣的擴(kuò)展,Spring中也有很多。
2.5.2 加載啟動指定類(重點)
這里會將我們的啟動類加載Spring容器beanDefinitionMap中,為后續(xù)SpringBoot自動化配置奠定基礎(chǔ),SpringBoot為我們提供的各種注解配置也與此有關(guān)。
load(context, sources.toArray(new Object[0]));
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug(
"Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
BeanDefinitionLoader loader = createBeanDefinitionLoader(
getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
loader.load();
}
這里參數(shù)即為我們項目啟動時傳遞的參數(shù):SpringApplication.run(SpringBootApplication.class, args);由于我們指定了啟動類,所以上面也就是加載啟動類到容器。需要注意的是,SpringBoot2會優(yōu)先選擇groovy加載方式,找不到再選用java方式?;蛟Sgroovy動態(tài)加載class文件的性能更勝一籌。
private int load(Class<?> source) {
if (isGroovyPresent()
&& GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
// Any GroovyLoaders added in beans{} DSL can contribute beans here
GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source,
GroovyBeanDefinitionSource.class);
load(loader);
}
if (isComponent(source)) {
//以注解的方式,將啟動類bean信息存入beanDefinitionMap
this.annotatedReader.register(source);
return 1;
}
return 0;
}
上面代碼中啟動類被加載到 beanDefinitionMap中,后續(xù)該啟動類將作為開啟自動化配置的入口。
2.5.3 通知監(jiān)聽器,容器已準(zhǔn)備就緒
listeners.contextLoaded(context);
主還是針對一些日志等監(jiān)聽器的響應(yīng)處理。
2.6 刷新容器
執(zhí)行到這里,SpringBoot相關(guān)的處理工作已經(jīng)結(jié)束,接下的工作就交給了Spring。
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
/**
* 刷新上下文環(huán)境
* 初始化上下文環(huán)境,對系統(tǒng)的環(huán)境變量或者系統(tǒng)屬性進(jìn)行準(zhǔn)備和校驗
* 如環(huán)境變量中必須設(shè)置某個值才能運(yùn)行,否則不能運(yùn)行,這個時候可以在這里加這個校驗,
* 重寫initPropertySources方法就好了
*/
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
/**
* 初始化BeanFactory,解析XML,相當(dāng)于之前的XmlBeanFactory的操作,
*/
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
/**
* 為上下文準(zhǔn)備BeanFactory,即對BeanFactory的各種功能進(jìn)行填充,如常用的注解@Autowired @Qualifier等
* 設(shè)置SPEL表達(dá)式#{key}的解析器
* 設(shè)置資源編輯注冊器,如PerpertyEditorSupper的支持
* 添加ApplicationContextAwareProcessor處理器
* 在依賴注入忽略實現(xiàn)*Aware的接口,如EnvironmentAware、ApplicationEventPublisherAware等
* 注冊依賴,如一個bean的屬性中含有ApplicationEventPublisher(beanFactory),則會將beanFactory的實例注入進(jìn)去
*/
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
/**
* 提供子類覆蓋的額外處理,即子類處理自定義的BeanFactoryPostProcess
*/
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
/**
* 激活各種BeanFactory處理器,包括BeanDefinitionRegistryBeanFactoryPostProcessor和普通的BeanFactoryPostProcessor
* 執(zhí)行對應(yīng)的postProcessBeanDefinitionRegistry方法 和 postProcessBeanFactory方法
*/
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
/**
* 注冊攔截Bean創(chuàng)建的Bean處理器,即注冊BeanPostProcessor,不是BeanFactoryPostProcessor,注意兩者的區(qū)別
* 注意,這里僅僅是注冊,并不會執(zhí)行對應(yīng)的方法,將在bean的實例化時執(zhí)行對應(yīng)的方法
*/
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
/**
* 初始化上下文中的資源文件,如國際化文件的處理等
*/
initMessageSource();
// Initialize event multicaster for this context.
/**
* 初始化上下文事件廣播器,并放入applicatioEventMulticaster,如ApplicationEventPublisher
*/
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
/**
* 給子類擴(kuò)展初始化其他Bean
*/
onRefresh();
// Check for listener beans and register them.
/**
* 在所有bean中查找listener bean,然后注冊到廣播器中
*/
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
/**
* 設(shè)置轉(zhuǎn)換器
* 注冊一個默認(rèn)的屬性值解析器
* 凍結(jié)所有的bean定義,說明注冊的bean定義將不能被修改或進(jìn)一步的處理
* 初始化剩余的非惰性的bean,即初始化非延遲加載的bean
*/
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
/**
* 初始化生命周期處理器DefaultLifecycleProcessor,DefaultLifecycleProcessor含有start方法和stop方法,spring啟動的時候調(diào)用start方法開始生命周期,
* spring關(guān)閉的時候調(diào)用stop方法來結(jié)束生命周期,通常用來配置后臺程序,啟動有一直運(yùn)行,如一直輪詢kafka
* 啟動所有實現(xiàn)了Lifecycle接口的類
* 通過spring的事件發(fā)布機(jī)制發(fā)布ContextRefreshedEvent事件,以保證對應(yīng)的監(jiān)聽器做進(jìn)一步的處理,即對那種在spring啟動后需要處理的一些類,這些類實現(xiàn)了
* ApplicationListener<ContextRefreshedEvent> ,這里就是要觸發(fā)這些類的執(zhí)行(執(zhí)行onApplicationEvent方法)另外,spring的內(nèi)置Event有ContextClosedEvent、ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent、RequestHandleEvent
* 完成初始化,通知生命周期處理器lifeCycleProcessor刷新過程,同時發(fā)出ContextRefreshEvent通知其他人
*/
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
refresh方法在Spring整個源碼體系中舉足輕重,是實現(xiàn)IOC和AOP的關(guān)鍵。
2.7 刷新容器后的擴(kuò)展接口
protected void afterRefresh(ConfigurableApplicationContext context,
ApplicationArguments args) {
}
擴(kuò)展接口,設(shè)計模式中的模板方法,默認(rèn)為空實現(xiàn)。如果有自定義需求,可以重寫該方法。比如打印一些啟動結(jié)束log,或者一些其它后置處理。
轉(zhuǎn)載自:SpringBoot | 第一篇:啟動流程源碼分析(上)