SpringBoot-啟動流程
平時開發springboot項目的時候,一個SpringBootApplication注解加一個main方法就可以啟動服務器運行起來(默認tomcat),看了下源碼,這里講下認為主要的流程
主要流程如下
0.啟動main方法開始
1.初始化配置:通過類加載器,(loadFactories)讀取classpath下所有的spring.factories配置文件,創建一些初始配置對象;通知監聽者應用程序啟動開始,創建環境對象environment,用於讀取環境配置 如 application.yml
2.創建應用程序上下文-createApplicationContext,創建 bean工廠對象
3.刷新上下文(啟動核心)
3.1 配置工廠對象,包括上下文類加載器,對象發布處理器,beanFactoryPostProcessor
3.2 注冊並實例化bean工廠發布處理器,並且調用這些處理器,對包掃描解析(主要是class文件)
3.3 注冊並實例化bean發布處理器 beanPostProcessor
3.4 初始化一些與上下文有特別關系的bean對象(創建tomcat服務器)
3.5 實例化所有bean工廠緩存的bean對象(剩下的)
3.6 發布通知-通知上下文刷新完成(啟動tomcat服務器)
4.通知監聽者-啟動程序完成
啟動中,大部分對象都是BeanFactory對象通過反射創建
SpringBoot的啟動解析代碼過多,下文是整體流程的部分主要代碼
啟動
啟動程序:
import org.springframework.boot.SpringApplication;//啟動類
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication //啟動必要注解
public class YourApplication {
//運行main方法啟動springboot
public static void main(String[] args) {
SpringApplication.run(YourApplication.class, args);//啟動類靜態run方法
}
}
啟動類
org.springframework.boot.SpringApplication
包含主流程方法
啟動類在運行靜態run方法的時候,是先創建一個SpringApplication對象,再運行對象的run方法,工廠初始配置在構造函數中完成,run方法定義運行總體流程
// 靜態方法 org.springframework.boot.SpringApplication.run(Class<?>[], String[])
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
// 構造方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
//..........
//// 1.(loadFactories)讀取classpath下所有的spring.factories配置文件 ////
// 配置應用程序啟動前的初始化對象
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 配置應用程序啟動前的監聽器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
// 對象run方法 開始啟動程序
public ConfigurableApplicationContext run(String... args) {
//......
// 通知監聽者啟動開始
listeners.starting();
try {
// 創建應用程序環境 配置文件在此處讀取(application.properties application.yml)
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
//// 2.創建應用程序上下文...此處創建了beanfactory ////
context = createApplicationContext();
//// 3.刷新上下文(spring啟動核心) ////
refreshContext(context);
//// 4.啟動完成通知...... ////
listeners.started(context);
}
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;
}
初始化配置
springboot啟動應用程序之前,會創建一些初始化對象和監聽器
這個操作在構造方法中完成,根據配置文件,創建ApplicationContextInitializer.class
,ApplicationListener.class
兩個接口的實現類,至於具體創建那些類對象,根據下面的方法邏輯去做
org.springframework.boot.SpringApplication.getSpringFactoriesInstances()
->
org.springframework.core.io.support.SpringFactoriesLoader.loadFactoryNames()
->
org.springframework.core.io.support.SpringFactoriesLoader.loadSpringFactories()
->
createSpringFactoriesInstances()
//構造方法中的初始化對象創建
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//看一下getSpringFactoriesInstances方法
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// 獲取初始化類的類名
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 通過這些類名實例化對象
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
// 讀取配置方法
// 更詳深層的代碼在org.springframework.core.io.support.SpringFactoriesLoader.loadSpringFactories(ClassLoader)
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
// loadSpringFactories(classLoader)讀取運行環境中所有META-INF/spring.factories配置
通過上面的方法,
spring-boot-2.2.8.RELEASE.jar/META-INF/spring.factories的文件中是這樣,
# 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.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
如果只讀取這一個文件,loadFactoryNames(ApplicationContextInitializer.class,classLoader)
讀取返回的就是下面的數組:
[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]
通過 Class.forName(className)
獲取這些類的Class,最后反射newInstance
創建這些對象
創建好這些對象后,啟動監聽器
listeners.starting(); // 這里也是一些調用操作
讀取application配置
監聽器啟動之后,會讀取application.properties 或者 application.yml文件
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); //此處application.properties配置文件會被讀取
創建應用上下文
初始化和配置好后,開始創建應用程序上下文,createApplicationContext ,關鍵的工廠BeanFactory就是此處創建,具體邏輯如下
// 創建應用程序上下文
context = createApplicationContext();
protected ConfigurableApplicationContext createApplicationContext() {
// 上下文創建的判斷邏輯
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_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);
}
public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
// 默認是創建這個類
這里通過this.webApplicationType判斷創建具體的應用上下文,也是反射創建對象,默認創建的是org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
對象,看一下這個類的基本信息
public class AnnotationConfigServletWebServerApplicationContext extends ServletWebServerApplicationContext
implements AnnotationConfigRegistry {
// 構造方法
public AnnotationConfigServletWebServerApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
}
創建工廠對象
此類繼承了很多類,其中一個父類是org.springframework.context.support.GenericApplicationContext
jvm機制,創建對象的時候,先運行父類的構造方法,所以創建了beanFactory
// 超級父類 GenericApplicationContext的構造方法
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();//創建工廠對象
}
刷新應用上下文
創建好上下文之后,開始刷新上下文,這里做了很多
工廠配置,bean處理器配置,類的掃描,解析,bean定義,bean類信息緩存,服務器創建,bean實例化,動態代理對象的創建等,
spring中注冊bean信息和實例化bean是兩件事情。
注冊bean信息不是創建bean對象,是解析bean類獲取詳細信息,會創建BeanDefinition對象,攜帶bean類的字節碼和方法等信息,把BeanDefinition對象注冊保存到工廠BeanDefinitionMap中。
工廠實例化bean時直接BeanDefinitionMap.get(beanName) 獲取bean的字節碼信息,通過反射創建對象,然后將bean對象保存到singletonObjects中。
refreshContext(context); //刷新上下文
默認實際對應的是org.springframework.context.support.AbstractApplicationContext
類的refresh()
方法
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//......
// 3.1配置工廠對象
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
// 3.2注冊並實例化bean工廠處理器,並調用他們
invokeBeanFactoryPostProcessors(beanFactory);
// 3.3注冊並實例化bean處理器
registerBeanPostProcessors(beanFactory);
// 3.4 初始化一些與上下文有特別關系的bean對象(創建tomcat)
onRefresh();
// 3.5 實例化所有bean工廠緩存的bean對象(剩下的).
finishBeanFactoryInitialization(beanFactory);
// 3.6 發布通知-通知上下文刷新完成(包括啟動tomcat)
finishRefresh();
}
catch (BeansException ex) {// ......Propagate exception to caller.
throw ex;
}
finally {// ......
resetCommonCaches();
}
}
}
配置工廠對象,包括上下文類加載器,bean工廠發布處理器
工廠創建好后,首先配置的是類加載器,然后是一些對象發布處理器(攔截器)
//// 3.1配置工廠對象
prepareBeanFactory(beanFactory);
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 設置類加載器
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 添加BeanPostProcessor
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
// ......
}
}
注冊並實例化bean工廠發布處理器,並調用他們
過程主要是工廠發布處理器的創建和調用,邏輯較多
//// 3.2注冊並實例化bean工廠處理器,並調用他們
invokeBeanFactoryPostProcessors(beanFactory);
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// ......
}
// PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
// 創建BeanDefinitionRegistryPostProcessor處理器
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
// 調用這些處理器
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
// ...
}
// 循環調用
private static void invokeBeanDefinitionRegistryPostProcessors(
Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanDefinitionRegistry(registry);
}
}
BeanDefinitionRegistryPostProcessor的子類對象在此處創建並調postProcessBeanDefinitionRegistry
方法。
其中org.springframework.context.annotation.ConfigurationClassPostProcessor
就是BeanDefinitionRegistryPostProcessor的子類,是一個spring的類解析器,掃描包下所有的類,解析出bean類,注冊到bean工廠由此類主要參與,其中有不少遞歸
注冊並實例化bean發布處理器
//// 3.3注冊並實例化bean處理器
registerBeanPostProcessors(beanFactory);
BeanFactoryPostProcessors 和 BeanPostProcessors是有區別的
BeanFactoryPostProcessors 是工廠發布處理器,定義什么是bean,知道哪些是bean類,解析class文件,包括注解解析,成員對象依賴解析等;BeanPostProcessors主要在BeanFactoryPostProcessors調用完之后工作
一般在bean對像的創建之前或之后,BeanFactory調用這些bean處理器攔截處理,Spring代理對象的創建也是通過beanPostProcessor處理器來實現
bean發布處理器生產AOP代理對象
AnnotationAwareAspectJAutoProxyCreator實現了BeanPostProcessors,在bean被工廠創建之后,BeanFactory調用攔截器的postProcessAfterInitialization做攔截處理。此攔截器處理器實際執行的是父類org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator
的方法
比如一個UserServiceImp類有@service注解,並且有切點Aspectj注解增強方法,bean工廠創建userServiceImp后,代理攔截器檢測到AOP相關注解,會創建動態代理對象userServiceImp$$EnhancerBySpringCGLIB並返代理對象,而不是返回userServiceImp
Spring工廠部分bean創建攔截代碼邏輯
// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(String, Object, RootBeanDefinition)
// bean初始化
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
invokeAwareMethods(beanName, bean);
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 初始化之前,攔截
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
invokeInitMethods(beanName, wrappedBean, mbd);
if (mbd == null || !mbd.isSynthetic()) {
// 初始化之后攔截
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
// 循環bean發布處理器調用postProcessAfterInitialization方法
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
AbstractAutoProxyCreator在此循環中被調用,比如在userServiceImp服務類上有事務注解@Transactional,一般就會被攔截生成代理對象,添加額外的處理事務的功能代碼,返回增強的代理對象
初始化一些與上下文有特別關系的bean對象
默認tomcat服務器的創建就是此方法完成,此處定義特別的bean創建,一般是服務器有關或個性化對象,
//// 3.4 初始化一些與上下文有特別關系的bean對象
onRefresh();
// org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext
// 子類context重寫
@Override
protected void onRefresh() {
super.onRefresh();
try {
createWebServer(); //創建服務器
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
ServletWebServerFactory factory = getWebServerFactory();
this.webServer = factory.getWebServer(getSelfInitializer());
// 默認創建tomcat服務器
// org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getWebServer()
}
// ......
initPropertySources();
}
實例化所有bean工廠緩存的bean對象
服務器啟動后,創建spring工廠里面緩存的bean信息(沒有被創建的單例)
//// 3.5 實例化所有bean工廠緩存的bean對象(剩下的).
finishBeanFactoryInitialization(beanFactory);
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// ......
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
}
// 子類org.springframework.beans.factory.support.DefaultListableBeanFactory實現方法,完成剩下的單例bean對象創建
@Override
public void preInstantiateSingletons() throws BeansException {
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
getBean(beanName); //創建還沒有實例化的bean對象
}
}
}
發布通知-通知上下文刷新完成
上下文初始化完成之后,啟動tomcat服務器
finishRefresh();
// super.finishRefresh
protected void finishRefresh() {
// ...... 發布刷行完成事件
// Publish the final event.
publishEvent(new ContextRefreshedEvent(this));
}
// org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.finishRefresh()
@Override
protected void finishRefresh() {
super.finishRefresh();
WebServer webServer = startWebServer();// 啟動服務器
if (webServer != null) {
publishEvent(new ServletWebServerInitializedEvent(webServer, this));
}
}
通知監聽者-啟動程序完成
發布通知監聽器啟動完成,監聽器會根據事件類型做個性化操作
listeners.started(context);
listeners.running(context);
void started(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.started(context);
}
}
void running(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.running(context);
}
}
@Override
public void started(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
}
@Override
public void running(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
}
不定期更新...