平時開發springboot項目的時候,一個SpringApplication註解加一個main方法就能夠啓動服務器運行起來(默認tomcat),看了下源碼,這裏講下認爲主要的流程java
主要流程以下web
0.啓動main方法開始spring
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.通知監聽者-啓動程序完成springboot
啓動中,大部分對象都是BeanFactory對象經過反射建立服務器
SpringBoot的啓動解析代碼過多,下文是總體流程的部分主要代碼app
啓動程序:jvm
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 發佈通知-通知上下文刷新完成 finishRefresh(); } catch (BeansException ex) {// ......Propagate exception to caller. throw ex; } finally {// ...... resetCommonCaches(); } } }
工廠建立好後,首先配置的是類加載器,而後是一些對象發佈處理器(攔截器)
//// 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); // ...... } }
過程主要是工廠發佈處理器的建立和調用,邏輯較多
//// 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工廠由此類主要參與,其中有很多遞歸
//// 3.3註冊並實例化bean處理器 registerBeanPostProcessors(beanFactory);
BeanFactoryPostProcessors 和 BeanPostProcessors是有區別的
BeanFactoryPostProcessors 是工廠發佈處理器,定義什麼是bean,知道哪些是bean類,解析class文件,包括註解解析,成員對象依賴解析等;BeanPostProcessors主要在BeanFactoryPostProcessors調用完以後工做
通常在bean對像的建立以前或以後,BeanFactory調用這些bean處理器攔截處理,Spring代理對象的建立也是經過beanPostProcessor處理器來實現
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,通常就會被攔截生成代理對象,添加額外的處理事務的功能代碼,返回加強的代理對象
默認tomcat服務器的建立就是此方法完成,此處定義特別的bean建立,通常是服務器有關或個性化對象,
//// 3.4 初始化一些與上下文有特別關係的bean對象(此處啓動tomcat服務器) onRefresh(); // org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext // 子類context重寫 @Override protected void onRefresh() { super.onRefresh(); try { createWebServer(); //建立tomcat服務器 } 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()); // 此處建立了服務器 // org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getWebServer() } // ...... initPropertySources(); }
服務器啓動後,建立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)); }
不按期更新...