1. 程式人生 > >SpringBoot啟動過程原始碼解析

SpringBoot啟動過程原始碼解析

一、啟動配置原理

幾個重要的事件回撥機制

配置在META-INF/spring.factories

ApplicationContextInitializer

SpringApplicationRunListener

只需要放在ioc容器中

ApplicationRunner

CommandLineRunner

啟動流程:斷點啟動Spring boot應用

1、下一步進入SpringApplication.run()中,此方法分為2個步驟

public static ConfigurableApplicationContext run(Object[] sources
, String[] args) { return new SpringApplication(sources).run(args);  //sources為主執行類的資訊 } 第一步:建立SpringApplication物件 第二步:執行run();
static ConfigurableApplicationContext run(Object[] sources, String[] args) { return new SpringApplication(sources).run(args);  //sources為主執行類的資訊 } 第一步:建立SpringApplication物件
第二步:執行run();

1.1 第一步SpringApplication建立

初始化引數,執行SpringApplication()方法

public SpringApplication(Object... sources) {
        initialize(sources);
} SpringApplication(Object... sources) {
        initialize(sources);
}

1.1.1 執行SpringApplication.initialize()

private void initialize(Object[] sources
) { if (sources != null && sources.length > 0) { this.sources.addAll(Arrays.asList(sources));//儲存主配置類 }    //判斷是否為web應用,通過classLoader判斷是否載入的有{ "javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext" } this.webEnvironment = deduceWebEnvironment();    //從類路徑下找到META-INF/spring.factories配置的所有ApplicationContextInitializer;然後儲存起來 setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class));    //從類路徑下找到ETA-INF/spring.factories配置的所有ApplicationListener setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass();//獲取到main方法所在的類 }
void initialize(Object[] sources) { if (sources != null && sources.length > 0) { this.sources.addAll(Arrays.asList(sources));//儲存主配置類 }    //判斷是否為web應用,通過classLoader判斷是否載入的有{ "javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext" } this.webEnvironment = deduceWebEnvironment();    //從類路徑下找到META-INF/spring.factories配置的所有ApplicationContextInitializer;然後儲存起來 setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class));    //從類路徑下找到ETA-INF/spring.factories配置的所有ApplicationListener setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass();//獲取到main方法所在的類 }

1.1.1.1 建立ApplicationContextInitializer

getSpringFactoriesInstances()說明: loadFactoryNames()獲取需要載入的類

private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
            Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        // 通過classLoader 從類路徑下找到META-INF/spring.factories配置的所有ApplicationContextInitializer集合,
        Set<String> names = new LinkedHashSet<String>(
                SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
                classLoader, args, names);  //建立例項
        AnnotationAwareOrderComparator.sort(instances); //排序
        return instances;
} <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
            Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        // 通過classLoader 從類路徑下找到META-INF/spring.factories配置的所有ApplicationContextInitializer集合,
        Set<String> names = new LinkedHashSet<String>(
                SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
                classLoader, args, names);  //建立例項
        AnnotationAwareOrderComparator.sort(instances); //排序
        return instances;
}

1.1.1.1.1 執行 SpringFactoriesLoader.loadFactoryNames()

說明:主要執行SpringFactoriesLoader.loadFactoryNames(type, classLoader),通過classLoader 從類路徑下找到META-INF/spring.factories配置的所有ApplicationContextInitializer

//獲取ApplicationContextInitializer 儲存起來
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
        try {
            //獲取所有jar下面的META-INF/spring.factories 檔案路徑
           //例如: jar:file:/C:/Users/Administrator/.m2/repository/org/springframework/boot/spring-boot/1.5.10.RELEASE/spring-boot-1.5.10.RELEASE.jar!/META-INF/spring.factories
            Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                    ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
            List<String> result = new ArrayList<String>();
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
                //讀取配置檔案中的ApplicationContextInitializer
                String factoryClassNames = properties.getProperty(factoryClassName);
                result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
            }
            return result;
        }
        catch (IOException ex) {
            throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
                    "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
        }
    }
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
        try {
            //獲取所有jar下面的META-INF/spring.factories 檔案路徑
           //例如: jar:file:/C:/Users/Administrator/.m2/repository/org/springframework/boot/spring-boot/1.5.10.RELEASE/spring-boot-1.5.10.RELEASE.jar!/META-INF/spring.factories
            Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                    ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
            List<String> result = new ArrayList<String>();
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
                //讀取配置檔案中的ApplicationContextInitializer
                String factoryClassNames = properties.getProperty(factoryClassName);
                result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
            }
            return result;
        }
        catch (IOException ex) {
            throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
                    "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
        }
    }

獲取的ApplicationContextInitializer

1.1.1.2 建立ApplicationListener

執行setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); 和ApplicationContextInitializer操作一樣;

從類路徑下找到ETA-INF/spring.factories配置的所有ApplicationListener

獲取的ApplicationListener 如下:

1.1.1.3 獲取配置類main()

從多個配置類中哪個類中有main()的主配置類

this.mainApplicationClass = deduceMainApplicationClass();
private Class<?> deduceMainApplicationClass() {
        try {
            StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
            for (StackTraceElement stackTraceElement : stackTrace) {
                if ("main".equals(stackTraceElement.getMethodName())) {  //判斷是否包含main方法
                    return Class.forName(stackTraceElement.getClassName());
                }
            }
        }
        catch (ClassNotFoundException ex) {
            // Swallow and continue
        }
        return null;
    } Class<?> deduceMainApplicationClass() {
        try {
            StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
            for (StackTraceElement stackTraceElement : stackTrace) {
                if ("main".equals(stackTraceElement.getMethodName())) {  //判斷是否包含main方法
                    return Class.forName(stackTraceElement.getClassName());
                }
            }
        }
        catch (ClassNotFoundException ex) {
            // Swallow and continue
        }
        return null;
    }

1.1.1.4 初始化結束

畫圈為initialize()方法執行儲存結果,和webEnvironment

QQ截圖.png

1.2 SpringApplication.run()方法

public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch(); //開始起止的監聽
        stopWatch.start();
        ConfigurableApplicationContext context = null;   //宣告IOC容器
        FailureAnalyzers analyzers = null;
        configureHeadlessProperty();//awt 相關,省略
    //獲取SpringApplicationRunListeners;從類路徑下META-INF/spring.factories
    //得到一個org.springframework.boot.context.event.EventPublishingRunListener
        SpringApplicationRunListeners listeners = getRunListeners(args);
     //回撥所有的獲取SpringApplicationRunListener.starting()方法
        listeners.starting();  //啟動
        try {
             //封裝命令列引數
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);
             //準備環境
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
            Banner printedBanner = printBanner(environment); //控制檯列印Spring banner圖示
              //建立ApplicationContext;決定建立web的ioc還是普通的ioc
            context = createApplicationContext();
            analyzers = new FailureAnalyzers(context);  //做異常處理報告用
         //準備上下文環境;將environment儲存到ioc中;而且applyInitializers();
         //applyInitializers():回撥之前儲存的所有的ApplicationContextInitializer的initialize方法
       //回撥所有的SpringApplicationRunListener的contextPrepared();
   //prepareContext執行完成以後回撥所有的SpringApplicationRunListener的contextLoaded();
            prepareContext(context, environment, listeners, applicationArguments,
                    printedBanner);
             //重新整理容器;ioc容器初始化(如果是web應用還會建立嵌入式的Tomcat);Spring註解版
             //掃描,建立,載入所有元件的地方;(配置類,元件,自動配置)
            refreshContext(context); //IOC建立完成
              //從ioc容器中獲取所有的ApplicationRunner和CommandLineRunner進行回撥
               //ApplicationRunner先回調,CommandLineRunner再回調
             afterRefresh(context, applicationArguments);
               //所有的SpringApplicationRunListener回撥finished方法
            listeners.finished(context, null);
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass)
                        .logStarted(getApplicationLog(), stopWatch);
            }
             //整個SpringBoot應用啟動完成以後返回啟動的ioc容器;
            return context; 
        }
        catch (Throwable ex) {
            handleRunFailure(context, listeners, analyzers, ex);
            throw new IllegalStateException(ex);
        }
    } ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch(); //開始起止的監聽
        stopWatch.start();
        ConfigurableApplicationContext context = null;   //宣告IOC容器
        FailureAnalyzers analyzers = null;
        configureHeadlessProperty();//awt 相關,省略
    //獲取SpringApplicationRunListeners;從類路徑下META-INF/spring.factories
    //得到一個org.springframework.boot.context.event.EventPublishingRunListener
        SpringApplicationRunListeners listeners = getRunListeners(args);
     //回撥所有的獲取SpringApplicationRunListener.starting()方法
        listeners.starting();  //啟動
        try {
             //封裝命令列引數
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);
             //準備環境
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
            Banner printedBanner = printBanner(environment); //控制檯列印Spring banner圖示
              //建立ApplicationContext;決定建立web的ioc還是普通的ioc
            context = createApplicationContext();
            analyzers = new FailureAnalyzers(context);  //做異常處理報告用
         //準備上下文環境;將environment儲存到ioc中;而且applyInitializers();
         //applyInitializers():回撥之前儲存的所有的ApplicationContextInitializer的initialize方法
       //回撥所有的SpringApplicationRunListener的contextPrepared();
   //prepareContext執行完成以後回撥所有的SpringApplicationRunListener的contextLoaded();
            prepareContext(context, environment, listeners, applicationArguments,
                    printedBanner);
             //重新整理容器;ioc容器初始化(如果是web應用還會建立嵌入式的Tomcat);Spring註解版
             //掃描,建立,載入所有元件的地方;(配置類,元件,自動配置)
            refreshContext(context); //IOC建立完成
              //從ioc容器中獲取所有的ApplicationRunner和CommandLineRunner進行回撥
               //ApplicationRunner先回調,CommandLineRunner再回調
             afterRefresh(context, applicationArguments);
               //所有的SpringApplicationRunListener回撥finished方法
            listeners.finished(context, null);
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass)
                        .logStarted(getApplicationLog(), stopWatch);
            }
             //整個SpringBoot應用啟動完成以後返回啟動的ioc容器;
            return context; 
        }
        catch (Throwable ex) {
            handleRunFailure(context, listeners, analyzers, ex);
            throw new IllegalStateException(ex);
        }
    }

1.2.1 獲取環境prepareEnvironment()

private ConfigurableEnvironment prepareEnvironment(
            SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments) {
        // 建立 或者 配置 the 環境
        ConfigurableEnvironment environment = getOrCreateEnvironment();
          //  配置環境
        configureEnvironment(environment, applicationArguments.getSourceArgs());
    //建立環境完成後回撥SpringApplicationRunListener.environmentPrepared();表示環境準備完成
        listeners.environmentPrepared(environment);
        if (!this.webEnvironment) {
            environment = new EnvironmentConverter(getClassLoader())
                    .convertToStandardEnvironmentIfNecessary(environment);
        }
        return environment;
}
​ ConfigurableEnvironment prepareEnvironment(
            SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments) {
        // 建立 或者 配置 the 環境
        ConfigurableEnvironment environment = getOrCreateEnvironment();
          //  配置環境
        configureEnvironment(environment, applicationArguments.getSourceArgs());
    //建立環境完成後回撥SpringApplicationRunListener.environmentPrepared();表示環境準備完成
        listeners.environmentPrepared(environment);
        if (!this.webEnvironment) {
            environment = new EnvironmentConverter(getClassLoader())
                    .convertToStandardEnvironmentIfNecessary(environment);
        }
        return environment;
}
​

1.2.2 準備上下文環境 prepareContext()

private void prepareContext(ConfigurableApplicationContext context,
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {
        context.setEnvironment(environment); //給IOC容器賦值environment
        postProcessApplicationContext(context); //IOC後置處理,註冊了元件
        applyInitializers(context);   //回撥之前儲存的所有的ApplicationContextInitializer的initialize方法
        listeners.contextPrepared(context);//執行所有Listeners的contextPrepared()方法
        if (this.logStartupInfo) {  //日誌記錄
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }
​
        // 把命令列引數的類applicationArguments 註冊到IOC容器
        context.getBeanFactory().registerSingleton("springApplicationArguments",
                applicationArguments);
        if (printedBanner != null) {
            //註冊列印的banner
            context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
        }
​
        // 獲取主類資訊
        Set<Object> sources = getSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        load(context, sources.toArray(new Object[sources.size()]));
    //prepareContext執行完成以後回撥所有的SpringApplicationRunListener的contextLoaded();
        listeners.contextLoaded(context);
} void prepareContext(ConfigurableApplicationContext context,
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {
        context.setEnvironment(environment); //給IOC容器賦值environment
        postProcessApplicationContext(context); //IOC後置處理,註冊了元件
        applyInitializers(context);   //回撥之前儲存的所有的ApplicationContextInitializer的initialize方法
        listeners.contextPrepared(context);//執行所有Listeners的contextPrepared()方法
        if (this.logStartupInfo) {  //日誌記錄
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }
​
        // 把命令列引數的類applicationArguments 註冊到IOC容器
        context.getBeanFactory().registerSingleton("springApplicationArguments",
                applicationArguments);
        if (printedBanner != null) {
            //註冊列印的banner
            context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
        }
​
        // 獲取主類資訊
        Set<Object> sources = getSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        load(context, sources.toArray(new Object[sources.size()]));
    //prepareContext執行完成以後回撥所有的SpringApplicationRunListener的contextLoaded();
        listeners.contextLoaded(context);
}

1.2.2.1 準備上下文環境 applyInitializers()

getInitializers() ;獲取到之前獲取的ApplicationContextInitializer 例項,執行initialize()方法

protected void applyInitializers(ConfigurableApplicationContext context) {
        for (ApplicationContextInitializer initializer : getInitializers()) {
            Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
                    initializer.getClass(), ApplicationContextInitializer.class);
            Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
            initializer.initialize(context);
        }
} void applyInitializers(ConfigurableApplicationContext context) {
        for (ApplicationContextInitializer initializer : getInitializers()) {
            Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
                    initializer.getClass(), ApplicationContextInitializer.class);
            Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
            initializer.initialize(context);
        }
}

1.2.3 重新整理容器refreshContext(context);

重新整理容器;ioc容器初始化(如果是web應用還會建立嵌入式的Tomcat);Spring註解版 掃描,建立,載入所有元件的地方;(配置類,元件,自動配置)

public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 準備此上下文以進行重新整理。
            prepareRefresh();
​
            // 告訴子類重新整理內部bean工廠。
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
​
            //準備使用這個beanFatory
             //配置工廠的標準上下文特性,
              //*如上下文的類載入器和後置處理器。
            prepareBeanFactory(beanFactory);
​
            try {
                // 允許在上下文子類中對bean工廠進行後處理。
                postProcessBeanFactory(beanFactory);
​
                // 呼叫工廠處理器在上下文中註冊為bean。
                invokeBeanFactoryPostProcessors(beanFactory);
​
                // 註冊bean處理器,攔截bean建立。
                registerBeanPostProcessors(beanFactory);
​
                // 初始化此上下文的訊息源。
                initMessageSource();
​
                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();
​
                // Initialize other special beans in specific context subclasses.
                onRefresh();
​
                // Check for listener beans and register them.
                registerListeners();
​
                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);
​
                // Last step: publish corresponding event.
                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();
            }
        }
} void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 準備此上下文以進行重新整理。
            prepareRefresh();
​
            // 告訴子類重新整理內部bean工廠。