Spring Boot系列(四):Spring Boot源碼解析

1、自動裝配原理

  以前博文已經講過,@SpringBootApplication繼承了@EnableAutoConfiguration,該註解導入了AutoConfigurationImport Selector,這個類主要是掃描spring-boot-autoconfigure下面的META-INF\spring.factories中的EnableAutoConfiguration對應的全類名,其中XXXAutoConfiguration都是一個個自動配置類。html

   自動裝配原理具體參考:Spring Boot系列(二):Spring Boot自動裝配原理解析
web

2、Spring Boot的jar啓動

  一、Spring Boot自動裝配Tomcat組件

  ① EmbeddedWebServerFactoryCustomizerAutoConfiguration內嵌的Web容器工廠定製器自動裝配類,裝配了TomcatWebServerFactoryCustomizer組件spring

   Tomcat工廠定製器TomcatWebServerFactoryCustomizer用來設置容器的屬性,把ServerProperties中的屬性設置到Tomcat容器的工廠中。服務器

   ServerProperties服務的屬性類:app

  ② ServletWebServerFactoryAutoConfiguration,ServletWeb工廠自動裝配類,裝配了以下四個組件less

  • ServletWebServerFactoryCustomizer:用來定製ServletWeb服務工廠
  • TomcatServletWebServerFactoryCustomizer:用來定製TomcatServletWeb服務工廠
  • ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar :後置處理器
  • ServletWebServerFactoryConfiguration:用來配置TomcatServletWeb服務工廠

   二、SpringApplication.run啓動流程

  ① new SpringApplication(primarySources),建立了一個SpringApplicationspring-boot

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        //設置主配置類 咱們本身寫的Spring Boot的啓動類
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        //設置web應用的類型
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        //設置容器初始化器(ApplicationContextInitializer類型的)
        setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
        //把監聽器設置到SpringApplication中[ApplicationListener]
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        //設置主配置類
        this.mainApplicationClass = deduceMainApplicationClass();
    }

  ② SpringApplication的run方法:this

  主要流程:spa

  第一:建立容器對象命令行

  第二:去META-INFO/spring.factories中獲取SpringApplicationRunListener監聽器(事件發佈監聽器)

  第三:發佈容器starting事件(經過spring的事件多播器)

  第四:封裝命令行參數

  第五:準備容器環境

  第六:打印Springboot的圖標

  第七:根據webApplicationType來建立容器

  第八:準備容器上下文

  第九:發佈容器啓動事件

  第十:發佈容器運行事件

public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        //容器對象
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        configureHeadlessProperty();
        //去META-INFO/spring.factories中獲取SpringApplicationRunListener監聽器(事件發佈監聽器)
        SpringApplicationRunListeners listeners = getRunListeners(args);
        //發佈容器starting事件(經過spring的事件多播器)
        listeners.starting();
        try {
            //封裝命令行參數
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            /**
             * 準備容器環境
             * 1: 獲取或者建立環境
             * 2:把命令行參數設置到環境中
             * 3:經過監聽器發佈環境準備事件
             */
            ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
            configureIgnoreBeanInfo(environment);
            //打印Springboot的圖標
            Banner printedBanner = printBanner(environment);
            //建立容器根據webApplicationType來建立容器(經過反射建立)
            context = createApplicationContext();
            exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
            /**
             * 準備上下文
             * 1:把環境設置到容器中
             * 2: 循環調用ApplicationContextInitializer進行容器初始化工做
             * 3: 發佈容器上下文準備完成事件
             * 4: 註冊關於Springboot特性的相關單例Bean
             * 5: 發佈容器上下文加載完畢事件
             */
            prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            refreshContext(context);
            //運行ApplicationRunner和CommandLineRunner
            afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
            }
            //發佈容器啓動事件
            listeners.started(context);
            //運行ApplicationRunner和CommandLineRunner
            callRunners(context, applicationArguments);
        }
        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;
    }

  ③ org.springframework.boot.SpringApplication#refreshContext

  ④ org.springframework.boot.SpringApplication#refresh

  ⑤ org.springframework.context.support.AbstractApplicationContext#refresh

  到了AbstractApplicationContext#refresh方法,以前講過Spring IoC源碼解析講過該方法的12大步,這裏就不細說,詳細能夠參考:Spring系列(三):Spring IoC源碼解析,裏面說過有一步就是onRefresh(),這個方法默認是空的,由子類根據自身須要去實現

  ⑥ org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh

  該onRefresh方法分2步

  第一:super.onRefresh(); 調用父類的onRefresh()

  第二:createWebServer();建立Web服務,很重要,很重要,很重要!!!

  ⑦ createWebServer()方法

  第一:ServletContext servletContext = getServletContext(); 獲取Servlet的上下文

  第二:ServletWebServerFactory factory = getWebServerFactory();獲取Tomcat的Web服務工廠

  第三:this.webServer = factory.getWebServer(getSelfInitializer()); 建立一個Web服務器

   ⑧ TomcatServletWebServerFactory#getWebServer()方法,主要用於建立一個Tomcat Web容器

   到此咱們知道Spring Boot的啓動經過Spring IoC的refresh中的的onRefresh()帶動了Tomcat的啓動,跟咱們以前咱們學Spring Mvc的時候恰好相反,Spring Mvc的是Tomcat的啓動帶動了Spring容器的啓動;

3、普通Web工程啓動

  一、普通的web工程,咱們找到web.xml,會發現都配置了以下的加載Spring的配置。

   二、Tomcat啓動的時候會調用該上下文加載的的監聽器的contextInitialized方法,咱們進入到該方法:

   三、進入初始化Web應用上下文initWebApplicationContext方法中:

  • this.context = createWebApplicationContext(servletContext);
  • configureAndRefreshWebApplicationContext(cwac, servletContext);

  四、進去到configureAndRefreshWebApplicationContext(cwac, servletContext)方法中:

   五、進入到refresh方法實際就到了org.springframework.context.support.AbstractApplicationContext#refresh的方法

  這個方法很熟悉了,Spring IoC的refresh的12大步;

4、Spring Boot啓動流程圖

相關文章
相關標籤/搜索