SpringBoot-啟動流程


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));
}

不定期更新...


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM