一、源碼分析
首先是項(xiàng)目啟動(dòng)類
public static void main(String[] args) {
SpringApplication.run(MarsApplication.class, args);
}
初始化時(shí)癣亚,會(huì)加載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)境類型纷纫,在后面會(huì)根據(jù)類型初始化對(duì)應(yīng)環(huán)境。ApplicationContextInitializer是spring組件spring-context組件中的一個(gè)接口三妈,主要是spring ioc容器刷新之前的一個(gè)回調(diào)接口,用于處于自定義邏輯莫绣。spring.factories文件中的實(shí)現(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個(gè)為:org.springframework.boot.autoconfigure.BackgroundPreinitializer
這10個(gè)監(jiān)聽器會(huì)貫穿SpringBoot整個(gè)生命周期畴蒲。
來看一下run方法:
public ConfigurableApplicationContext run(String... args) {
//時(shí)間監(jiān)控
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
//java.awt.headless是J2SE的一種模式用于在缺少顯示屏、鍵盤或者鼠標(biāo)時(shí)的系統(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
//第一步:獲取并啟動(dòng)監(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();
//第四步:實(shí)例化SpringBootExceptionReporter.class蔫骂,用來支持報(bào)告關(guān)于啟動(dòng)的錯(cuò)誤
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;
}
- 第一步:獲取并啟動(dòng)監(jiān)聽器
- 第二步:構(gòu)造容器環(huán)境
- 第三步:創(chuàng)建容器
- 第四步:實(shí)例化SpringBootExceptionReporter.class,用來支持報(bào)告關(guān)于啟動(dòng)的錯(cuò)誤
- 第五步:準(zhǔn)備容器
- 第六步:刷新容器
- 第七步:刷新容器后的擴(kuò)展接口
二牺汤、步驟分析
2.1 獲取并啟動(dòng)監(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)前對(duì)象作為參數(shù)补胚,該方法用來獲取spring.factories
對(duì)應(yīng)的監(jiān)聽器:
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
整個(gè)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)建實(shí)例
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException(
"Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
上面通過反射獲取實(shí)例時(shí)會(huì)觸發(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);
}
}
重點(diǎn)來看一下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)部類對(duì)象
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
上述方法定義在SimpleApplicationEventMulticaster父類AbstractApplicationEventMulticaster中码耐。關(guān)鍵代碼為this.defaultRetriever.applicationListeners.add(listener);
,這是一個(gè)內(nèi)部類溶其,用來保存所有的監(jiān)聽器骚腥。也就是在這一步,將spring.factories
中的監(jiān)聽器傳遞到SimpleApplicationEventMulticaster中瓶逃。
2.1.2 啟動(dòng)監(jiān)聽器
listeners.starting();
,獲取的監(jiān)聽器為EventPublishingRunListener束铭,從名字可以看出是啟動(dòng)事件發(fā)布監(jiān)聽器,主要用來發(fā)布啟動(dòng)事件厢绝。
@Override
public void starting() {
//關(guān)鍵代碼契沫,這里是創(chuàng)建application啟動(dòng)事件`ApplicationStartingEvent`
this.initialMulticaster.multicastEvent(
new ApplicationStartingEvent(this.application, this.args));
}
EventPublishingRunListener這個(gè)是SpringBoot框架中最早執(zhí)行的監(jiān)聽器,在該監(jiān)聽器執(zhí)行started()
方法時(shí)代芜,會(huì)繼續(xù)發(fā)布事件埠褪,也就是事件傳遞。這種實(shí)現(xiàn)主要還是基于Spring的事件機(jī)制挤庇。繼續(xù)跟進(jìn)SimpleApplicationEventMulticaster钞速,有個(gè)核心方法:
@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);
}
}
}
這里會(huì)根據(jù)事件類型ApplicationStartingEvent獲取對(duì)應(yīng)的監(jiān)聽器昆咽,在容器啟動(dòng)之后執(zhí)行響應(yīng)的動(dòng)作驾凶。
這是SpringBoot啟動(dòng)過程中,第一處根據(jù)類型掷酗,執(zhí)行監(jiān)聽器的地方调违。根據(jù)發(fā)布的事件類型從上述10種監(jiān)聽器中選擇對(duì)應(yīng)的監(jiān)聽器進(jìn)行事件發(fā)布,當(dāng)然如果繼承了 SpringCloud或者別的框架泻轰,就不止10個(gè)了技肩。這里選了一個(gè) SpringBoot 的日志監(jiān)聽器來進(jìn)行講解,核心代碼如下:
@Override
public void onApplicationEvent(ApplicationEvent event) {
//在springboot啟動(dòng)的時(shí)候
if (event instanceof ApplicationStartedEvent) {
onApplicationStartedEvent((ApplicationStartedEvent) event);
}
//springboot的Environment環(huán)境準(zhǔn)備完成的時(shí)候
else if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent(
(ApplicationEnvironmentPreparedEvent) event);
}
//在springboot容器的環(huán)境設(shè)置完成以后
else if (event instanceof ApplicationPreparedEvent) {
onApplicationPreparedEvent((ApplicationPreparedEvent) event);
}
//容器關(guān)閉的時(shí)候
else if (event instanceof ContextClosedEvent && ((ContextClosedEvent) event)
.getApplicationContext().getParent() == null) {
onContextClosedEvent();
}
//容器啟動(dòng)失敗的時(shí)候
else if (event instanceof ApplicationFailedEvent) {
onApplicationFailedEvent();
}
}
因?yàn)槲覀兊氖录愋蜑锳pplicationEvent浮声,所以會(huì)執(zhí)行onApplicationStartedEvent((ApplicationStartedEvent) event);
虚婿。SpringBoot會(huì)在運(yùn)行過程中的不同階段,發(fā)送各種事件泳挥,來執(zhí)行對(duì)應(yīng)監(jiān)聽器的對(duì)應(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
//獲取對(duì)應(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)境對(duì)象是StandardServletEnvironment。
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
if (this.webApplicationType == WebApplicationType.SERVLET) {
return new StandardServletEnvironment();
}
return new StandardEnvironment();
}
枚舉類WebApplicationType是SpringBoot2新增的特性辛蚊,主要針對(duì)spring5引入的reactive特性粤蝎。枚舉類型如下:
public enum WebApplicationType {
//不需要再web容器的環(huán)境下運(yùn)行,普通項(xiàng)目
NONE,
//基于servlet的web項(xiàng)目
SERVLET,
//這個(gè)是spring5版本開始的新特性
REACTIVE
}
Environment接口提供了4種實(shí)現(xiàn)方式袋马,StandardEnvironment初澎、StandardServletEnvironment和MockEnvironment、StandardReactiveWebEnvironment虑凛,分別代表普通程序碑宴、Web程序、測(cè)試程序的環(huán)境桑谍、響應(yīng)式web環(huán)境延柠。
在返回return new StandardServletEnvironment();
對(duì)象的時(shí)候,會(huì)完成一系列初始化動(dòng)作锣披,主要就是將運(yùn)行機(jī)器的系統(tǒng)變量和環(huán)境變量贞间,加入到其父類AbstractEnvironment定義的對(duì)象MutablePropertySources中,MutablePropertySources對(duì)象中定義了一個(gè)屬性集合:
private final List<PropertySource<?>> propertySourceList = new CopyOnWriteArrayList<PropertySource<?>>();
執(zhí)行到這里雹仿,系統(tǒng)變量和環(huán)境變量已經(jīng)被載入到配置文件的集合中增热,接下來就行解析項(xiàng)目中的配置文件。來看一下listeners.environmentPrepared(environment);
胧辽,上面已經(jīng)提到了峻仇,這里是第二次發(fā)布事件。什么事件呢邑商?顧名思義摄咆,系統(tǒng)環(huán)境初始化完成的事件。
可以看到獲取到的監(jiān)聽器和第一次發(fā)布啟動(dòng)事件獲取的監(jiān)聽器有幾個(gè)是重復(fù)的人断,這也驗(yàn)證了監(jiān)聽器是可以多次獲取吭从,根據(jù)事件類型來區(qū)分具體處理邏輯。上面介紹日志監(jiān)聽器的時(shí)候已經(jīng)提到恶迈。主要來看一下ConfigFileApplicationListener涩金,該監(jiān)聽器非常核心,主要用來處理項(xiàng)目配置蝉绷。項(xiàng)目中的 properties 和yml文件都是其內(nèi)部類所加載鸭廷。
首先還是會(huì)去讀spring.factories 文件枣抱,List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
獲取的處理類有以下四種:
# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor= //一個(gè)@FunctionalInterface函數(shù)式接口
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor熔吗,//為springCloud提供的擴(kuò)展類
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,//支持json環(huán)境變量
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor //springBoo2提供的一個(gè)包裝類佳晶,主要將`StandardServletEnvironment`包裝成`SystemEnvironmentPropertySourceEnvironmentPostProcessor`對(duì)象
在執(zhí)行完上述三個(gè)監(jiān)聽器流程后桅狠,ConfigFileApplicationListener會(huì)執(zhí)行該類本身的邏輯。由其內(nèi)部類Loader加載項(xiàng)目制定路徑下的配置文件:
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)行判斷的中跌,因?yàn)樵擃愋蜑镾ERVLET類型咨堤,所以會(huì)通過反射裝載對(duì)應(yīng)的字節(jié)碼,如下:
public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
該對(duì)象是SpringBoot2創(chuàng)建的容器漩符,后續(xù)所有的操作都會(huì)基于該容器一喘。
2.4 報(bào)告錯(cuò)誤信息
這里還是以同樣的方式獲取spring.factories文件中的指定類:
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
該類主要是在項(xiàng)目啟動(dòng)失敗之后,打印log:
private void reportFailure(Collection<SpringBootExceptionReporter> exceptionReporters,Throwable failure) {
try {
for (SpringBootExceptionReporter reporter : exceptionReporters) {
if (reporter.reportException(failure)) {
//上報(bào)錯(cuò)誤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)備動(dòng)作嗜暴。包含一個(gè)非常關(guān)鍵的操作:將啟動(dòng)類注入容器凸克,為后續(xù)開啟自動(dòng)化配置奠定基礎(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和自定義的實(shí)例)
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
//注冊(cè)啟動(dòng)參數(shù)bean,這里將容器指定的參數(shù)封裝成bean舆逃,注入容器
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
//設(shè)置banner
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// Load the sources
//獲取我們的啟動(dòng)類指定的參數(shù)蚂维,可以是多個(gè)
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
//加載我們的啟動(dòng)類,將啟動(dòng)類注入容器
load(context, sources.toArray(new Object[0]));
//發(fā)布容器已加載事件路狮。
listeners.contextLoaded(context);
}
來看一下上面的幾個(gè)核心處理
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í)行任何邏輯虫啥,因?yàn)閎eanNameGenerator和resourceLoader默認(rèn)為空。之所以這樣做览祖,是SpringBoot留給我們的擴(kuò)展處理方式遇西,類似于這樣的擴(kuò)展,Spring中也有很多杰赛。
2.5.2 加載啟動(dòng)指定類(重點(diǎn))
這里會(huì)將我們的啟動(dòng)類加載Spring容器beanDefinitionMap中乖坠,為后續(xù)SpringBoot自動(dòng)化配置奠定基礎(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ù)即為我們項(xiàng)目啟動(dòng)時(shí)傳遞的參數(shù):SpringApplication.run(SpringBootApplication.class, args);
由于我們指定了啟動(dòng)類柳骄,所以上面也就是加載啟動(dòng)類到容器。需要注意的是箕般,SpringBoot2會(huì)優(yōu)先選擇groovy加載方式耐薯,找不到再選用java方式∷坷铮或許groovy動(dòng)態(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)) {
//以注解的方式,將啟動(dòng)類bean信息存入beanDefinitionMap
this.annotatedReader.register(source);
return 1;
}
return 0;
}
上面代碼中啟動(dòng)類被加載到 beanDefinitionMap中杯聚,后續(xù)該啟動(dòng)類將作為開啟自動(dòng)化配置的入口臼婆。
2.5.3 通知監(jiān)聽器,容器已準(zhǔn)備就緒
listeners.contextLoaded(context);
主還是針對(duì)一些日志等監(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)境颁独,對(duì)系統(tǒng)的環(huán)境變量或者系統(tǒng)屬性進(jìn)行準(zhǔn)備和校驗(yàn)
* 如環(huán)境變量中必須設(shè)置某個(gè)值才能運(yùn)行彩届,否則不能運(yùn)行,這個(gè)時(shí)候可以在這里加這個(gè)校驗(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坯墨,即對(duì)BeanFactory的各種功能進(jìn)行填充,如常用的注解@Autowired @Qualifier等
* 設(shè)置SPEL表達(dá)式#{key}的解析器
* 設(shè)置資源編輯注冊(cè)器病往,如PerpertyEditorSupper的支持
* 添加ApplicationContextAwareProcessor處理器
* 在依賴注入忽略實(shí)現(xiàn)*Aware的接口捣染,如EnvironmentAware、ApplicationEventPublisherAware等
* 注冊(cè)依賴停巷,如一個(gè)bean的屬性中含有ApplicationEventPublisher(beanFactory)耍攘,則會(huì)將beanFactory的實(shí)例注入進(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í)行對(duì)應(yīng)的postProcessBeanDefinitionRegistry方法 和 postProcessBeanFactory方法
*/
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
/**
* 注冊(cè)攔截Bean創(chuàng)建的Bean處理器畔勤,即注冊(cè)BeanPostProcessor蕾各,不是BeanFactoryPostProcessor,注意兩者的區(qū)別
* 注意庆揪,這里僅僅是注冊(cè)式曲,并不會(huì)執(zhí)行對(duì)應(yīng)的方法,將在bean的實(shí)例化時(shí)執(zhí)行對(duì)應(yīng)的方法
*/
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
/**
* 初始化上下文中的資源文件缸榛,如國(guó)際化文件的處理等
*/
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,然后注冊(cè)到廣播器中
*/
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
/**
* 設(shè)置轉(zhuǎn)換器
* 注冊(cè)一個(gè)默認(rèn)的屬性值解析器
* 凍結(jié)所有的bean定義内颗,說明注冊(cè)的bean定義將不能被修改或進(jìn)一步的處理
* 初始化剩余的非惰性的bean钧排,即初始化非延遲加載的bean
*/
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
/**
* 初始化生命周期處理器DefaultLifecycleProcessor,DefaultLifecycleProcessor含有start方法和stop方法均澳,spring啟動(dòng)的時(shí)候調(diào)用start方法開始生命周期恨溜,
* spring關(guān)閉的時(shí)候調(diào)用stop方法來結(jié)束生命周期,通常用來配置后臺(tái)程序找前,啟動(dòng)有一直運(yùn)行糟袁,如一直輪詢kafka
* 啟動(dòng)所有實(shí)現(xiàn)了Lifecycle接口的類
* 通過spring的事件發(fā)布機(jī)制發(fā)布ContextRefreshedEvent事件,以保證對(duì)應(yīng)的監(jiān)聽器做進(jìn)一步的處理躺盛,即對(duì)那種在spring啟動(dòng)后需要處理的一些類项戴,這些類實(shí)現(xiàn)了
* ApplicationListener<ContextRefreshedEvent> ,這里就是要觸發(fā)這些類的執(zhí)行(執(zhí)行onApplicationEvent方法)另外,spring的內(nèi)置Event有ContextClosedEvent颗品、ContextRefreshedEvent肯尺、ContextStartedEvent、ContextStoppedEvent躯枢、RequestHandleEvent
* 完成初始化则吟,通知生命周期處理器lifeCycleProcessor刷新過程,同時(shí)發(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整個(gè)源碼體系中舉足輕重锄蹂,是實(shí)現(xiàn)IOC和AOP的關(guān)鍵氓仲。
2.7 刷新容器后的擴(kuò)展接口
protected void afterRefresh(ConfigurableApplicationContext context,
ApplicationArguments args) {
}
擴(kuò)展接口,設(shè)計(jì)模式中的模板方法得糜,默認(rèn)為空實(shí)現(xiàn)敬扛。如果有自定義需求,可以重寫該方法朝抖。比如打印一些啟動(dòng)結(jié)束log啥箭,或者一些其它后置處理。
轉(zhuǎn)載自:SpringBoot | 第一篇:?jiǎn)?dòng)流程源碼分析(上)