SpringBoot啓動過程原理

最近這兩年springboot忽然火起來了,那麼咱們就來看看springboot的運行原理。java

一。springboot的三種啓動方式:web

1.運行帶有main方法的
2.經過命令 Java -jar命令
3.經過spring-boot-plugin的方式spring

二。springboot 啓動時執行方法,有兩種方式編程

第一種方式是用啓動時的main方法加載靜態方法。springboot

另外一種是用初始化註解@postconstruct 執行。(注意點必須void而且參數)。app

注意點:【1.@PostConstruct會先被執行,靜態方法後被執行。2.若是須要參數的話,只能用靜態方法的方式框架

SpringBoot啓動過程原理

從上面代碼看,調用了SpringApplication的靜態方法run。這個run方法會構造一個SpringApplication的實例,而後再調用這裏實例的run方法就表示啓動SpringBoot。less

具體對象處理流程看下邊時序圖:ide

概述:spring-boot

1.構造SpringApplication的實例(時序圖步驟1-2)
2.調用SpringApplication.run()方法(時序圖步驟3)
3.構造SpringApplicationRunListeners 實例(時序圖步驟3.1.1)
4.發佈ApplicationStartedEvent事件(時序圖步驟3.1.2)
5.SpringApplicationRunListeners 實例準備環境信息(時序圖步驟3.1.3)
6.建立ApplicationContext對象(時序圖步驟3.1.4)
7.ApplicationContext實例準備環境信息(時序圖步驟3.1.5)
8.刷新的上下文(時序圖步驟3.1.6)

 

 

2.啓動加載過程分析

1.2.1 構造SpringApplication的實例(時序圖步驟1-2)
代碼

public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
        // 步驟1
        return new SpringApplication(sources).run(args);
}
public SpringApplication(Object... sources) {
        // 步驟1.1
        initialize(sources);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
    private void initialize(Object[] sources) {
        if (sources != null && sources.length > 0) {
            this.sources.addAll(Arrays.asList(sources));
        }
        this.webEnvironment = deduceWebEnvironment();
        //加載META-INF/spring.factories路徑ApplicationContextInitializer.class
        getSpringFactoriesInstances(
                ApplicationContextInitializer.class));
        setListeners((Collection) 
        //加載META-INF/spring.factories路徑ApplicationListener.class
        getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = deduceMainApplicationClass();
    }

分析
⑴.經過ClassLoader.getResources加載META-INF/spring.factories路徑下的
文件信息,從中找key爲ApplicationContextInitializer.class,並實例化。
⑵.經過ClassLoader.getResources加載META-INF/spring.factories路徑下的
文件信息ApplicationListener.class對應類,並實例化。

1.2.2 調用SpringApplication.run()方法(時序圖步驟3)
代碼:

public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        FailureAnalyzers analyzers = null;
        configureHeadlessProperty();
        //  步驟3.1.1
        SpringApplicationRunListeners listeners = getRunListeners(args);
        // 步驟3.1.2
        listeners.starting();
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);
            // 步驟 3.1.3
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
            Banner printedBanner = printBanner(environment);
            // 步驟3.1.4
            context = createApplicationContext();
            analyzers = new FailureAnalyzers(context);
            // 步驟3.1.5
            prepareContext(context, environment, listeners, applicationArguments,
                    printedBanner);
            // 步驟3.1.6
            refreshContext(context);
            // 步驟3.1.7
            afterRefresh(context, applicationArguments);
            // 步驟3.1.8
            listeners.finished(context, null);
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass)
                        .logStarted(getApplicationLog(), stopWatch);
            }
            return context;
        }
        catch (Throwable ex) {
            handleRunFailure(context, listeners, analyzers, ex);
            throw new IllegalStateException(ex);
        }
    }

 

1.2.2 步驟3.1.1:
代碼

private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
        // (1)
        return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
                SpringApplicationRunListener.class, types, this, args));
    }
1
2
3
4
5
6
分析 
(1). 經過ClassLoader.getResources加載META-INF/spring.factories路徑下的 
文件信息,從中找key爲SpringApplicationRunListener對應類,並實例化。
1.2.3 步驟3.1.2:
代碼

public void starting() {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.starting();
        }
    }
    @Override
    @SuppressWarnings("deprecation")
    public void starting() {
        this.initialMulticaster
                .multicastEvent(new ApplicationStartedEvent(this.application, this.args));
    }

分析 
:發佈ApplicationStartedEvent事件。

 

 

1.2.4 步驟3.1.3:
代碼

private ConfigurableEnvironment prepareEnvironment(
            SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments) {
        // Create and configure the environment
        // ⑴. 獲得環境對象ConfigurableEnvironment
        ConfigurableEnvironment environment = getOrCreateEnvironment();
        // ⑵. 並配置環境信息;對listeners初始化環境屬性
        configureEnvironment(environment, applicationArguments.getSourceArgs());
        // ⑶. 發佈ApplicationEnvironmentPreparedEvent事件。
        listeners.environmentPrepared(environment);
        if (isWebEnvironment(environment) && !this.webEnvironment) {
            environment = convertToStandardEnvironment(environment);
        }
        return environment;
    }

分析 
⑴. 獲得環境對象ConfigurableEnvironment 
⑵. 並配置環境信息;對listeners初始化環境屬性。 
⑶. 發佈ApplicationEnvironmentPreparedEvent事件。

 

步驟3.1.4:
分析 
建立ApplicationContext對象 ,其中在實例化ApplicationContext子類 
AnnotationConfigApplicationContext時,如代碼:

public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}

會建立AnnotatedBeanDefinitionReader對象檢測是否須要將一下對象放到Spring上下文中

// 用戶配置Configuration註解,實現了BeanDefinitionRegistryPostProcessor接口
ConfigurationClassPostProcessor
// 用於配置Autowired註解,實現了MergedBeanDefinitionPostProcessor接口
AutowiredAnnotationBeanPostProcessor
// 用於配置Required註解,實現了MergedBeanDefinitionPostProcessor接口
RequiredAnnotationBeanPostProcessor
// 用於配置JSR-250註解,實現了InstantiationAwareBeanPostProcessor接口
CommonAnnotationBeanPostProcessor
// 用於配置JPA註解
PersistenceAnnotationBeanPostProcessor
// 用於配置EventListener註解,實現了SmartInitializingSingleton接口
EventListenerMethodProcessor
// EventListener工廠
DefaultEventListenerFactory

 

步驟3.1.5:
代碼

private void prepareContext(ConfigurableApplicationContext context,
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {
        // ⑴.對ApplicationContext設置環境變量;
        context.setEnvironment(environment);
        // ⑵.配置屬性ResourceLoader和ClassLoader屬性;
        postProcessApplicationContext(context);
        // ⑶.循環初始化繼承了
        applyInitializers(context);
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }

        // Add boot specific singleton beans
        context.getBeanFactory().registerSingleton("springApplicationArguments",
                applicationArguments);
        if (printedBanner != null) {
            context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
        }

        // Load the sources
        Set<Object> sources = getSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        load(context, sources.toArray(new Object[sources.size()]));
        listeners.contextLoaded(context);
    }

 

分析: 
⑴.對ApplicationContext設置環境變量; 
⑵.配置屬性ResourceLoader和ClassLoader屬性; 
⑶.調用步驟1查詢出來ApplicationContextInitializer子類,循環調用initialize()方法。

 

@SuppressWarnings({ "rawtypes", "unchecked" })
    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);
        }
    }

⑷.發佈ApplicationPreparedEvent事件。

 

步驟3.1.6
代碼:

@Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // ⑴.準備刷新的上下文環境
            prepareRefresh();

            // ⑵.初始化BeanFactory
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // ⑶.對BeanFactory進行各類功能填充
            prepareBeanFactory(beanFactory);

            try {
                // ⑷.子類覆蓋方法作額外的處理
                postProcessBeanFactory(beanFactory);

                // ⑸.激活各類BeanFactory處理器
                invokeBeanFactoryPostProcessors(beanFactory);

                // ⑹.註冊攔截Bean建立的Bean處理,這裏只是註冊,真正調用是再拿去Bean的時候
                registerBeanPostProcessors(beanFactory);

                // ⑺.爲上下文初始化Message源,即不一樣語言的消息體,國際化處理
                initMessageSource();

                // ⑻.初始化應用消息廣播器,並放到applicationEventMulticaster bean中
                initApplicationEventMulticaster();

                // ⑼.留給子類來初始化其餘bean
                onRefresh();

                // ⑽.在全部註冊的bean中查找Listener bean,註冊到消息廣播中
                registerListeners();

                // ⑾.初始化剩下的單實例(非惰性)
                finishBeanFactoryInitialization(beanFactory);

                // ⑿.完成刷新過程,通知生命週期處理器lifecycleProcessor刷新過程,同時發出ContextRefreshEvent通知別人
                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();
            }
        }
    }

分析:

⑴.準備刷新的上下文環境
⑵.初始化BeanFactory
⑶.對BeanFactory進行各類功能填充
⑷.子類覆蓋方法作額外的處理
⑸.激活各類BeanFactory處理器
⑹.註冊攔截Bean建立的Bean處理,這裏只是註冊,真正調用是再拿去Bean的時候
⑺.爲上下文初始化Message源,即不一樣語言的消息體,國際化處理
⑻.初始化應用消息廣播器,並放到applicationEventMulticaster bean中
⑼.留給子類來初始化其餘bean
⑽.在全部註冊的bean中查找Listener bean,註冊到消息廣播中
⑾.初始化剩下的單實例(非惰性)
⑿.完成刷新過程,通知生命週期處理器lifecycleProcessor刷新過程,同時發出ContextRefreshEvent通知別人

 

 

總結:

Spring 是一個「引擎」 
Spring MVC 是基於 Spring 的一個 MVC 框架 
Spring Boot 是基於 Spring4 的條件註冊的一套快速開發整合包 

Spring 最初利用「工廠模式」( DI )和「代理模式」( AOP )解耦應用組件,並構建了一些列功能組件。你們以爲挺好用,因而按照 MVC 框架模式,(用Spring 解耦的組件)搞了一個MVC用來開發 web 應用也就是( SpringMVC )。而後有發現每次開發都要搞不少依賴,寫不少樣板代碼很麻煩,因而搞了一些懶人整合包( starter ),這套就是 Spring Boot 。  
spring 框架有超多的延伸產品例如 boot security jpa etc... 但它的基礎就是 spring 的 ioc 和 aop ioc 提供了依賴注入的容器 aop 解決了面向橫切面的編程 而後在此二者的基礎上實現了其餘延伸產品的高級功能 Spring MVC 呢是基於 Servlet 的一個 MVC 框架 主要解決 WEB 開發的問題 由於 Spring 的配置太複雜了 各類 XML JavaConfig hin 麻煩 因而懶人改變世界推出了 Spring boot 約定優於配置 簡化了 spring 的配置流程 簡單談下本身的理解   以上來自度娘,感受和本身的理解至關。直接拿來用,佔個坑。之後完善。

 

springApplication能夠讀取不一樣種類的源文件:

  • 類- java類由AnnotatedBeanDefinitionReader加載。
  • Resource - xml資源文件由XmlBeanDefinitionReader讀取, 或者groovy腳本由GroovyBeanDefinitionReader讀取
  • Package - java包文件由ClassPathBeanDefinitionScanner掃描讀取。
  • CharSequence - 字符序列能夠是類名、資源文件、包名,根據不一樣方式加載。若是一個字符序列不能夠解析程序到類,也不能夠解析到資源文件,那麼就認爲它是一個包。
相關文章
相關標籤/搜索