SpringBoot-啓動流程

SpringBoot-啓動流程

平時開發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();
        }
    }
}

配置工廠對象,包括上下文類加載器,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對象(此處啓動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();
}

實例化全部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));
}

不按期更新...

相關文章
相關標籤/搜索