1. 程式人生 > >springboot部署到tomcat啟動,以及線上部署,原始碼分析

springboot部署到tomcat啟動,以及線上部署,原始碼分析

1.專案環境說明:

tomcat8.5.11, springboot 1.5.6.RELEASE,maven3.3.9

2.war包eclipse配置tomcat啟動。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.xxx</groupId>
    <artifactId>xxx-parent</artifactId>
    <version>1.0.0-SNAPSHOT</version>
  </parent>
  <artifactId>service</artifactId>
  
  <packaging>war</packaging>
  
  <properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
		<transaction.version>4.0.4</transaction.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.3.2</version>
        </dependency>
        <dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
		</plugins>
		<finalName>provider</finalName>
	</build>
</project>

Application程式碼修改

@SpringBootApplication
@EnableTransactionManagement
@EnableScheduling
@EnableAutoConfiguration
public class Application  extends SpringBootServletInitializer {
	
	@Override
	protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
		return application.sources(Application.class);
	}

}

3.war包tomcat線上部署

eclipse export war包。

把war包放到tomcat webapps目錄下。

bin目錄下./startup.sh

4.原始碼分析

jar包:執行SpringBoot主類的main方法,啟動ioc容器,建立嵌入式的Servlet容器;

war包:啟動伺服器,伺服器啟動SpringBoot應用【SpringBootServletInitializer】,啟動ioc容器;


servlet3.0(Spring註解版):

8.2.4 Shared libraries / runtimes pluggability:

規則:

	1)、伺服器啟動(web應用啟動)會建立當前web應用裡面每一個jar包裡面ServletContainerInitializer例項:

	2)、ServletContainerInitializer的實現放在jar包的META-INF/services資料夾下,有一個名為javax.servlet.ServletContainerInitializer的檔案,內容就是ServletContainerInitializer的實現類的全類名

	3)、還可以使用@HandlesTypes,在應用啟動的時候載入我們感興趣的類;



流程:

1)、啟動Tomcat

2)、org\springframework\spring-web\4.3.14.RELEASE\spring-web-4.3.14.RELEASE.jar!\META-INF\services\javax.servlet.ServletContainerInitializer:

Spring的web模組裡面有這個檔案:org.springframework.web.SpringServletContainerInitializer

3)、SpringServletContainerInitializer將@HandlesTypes(WebApplicationInitializer.class)標註的所有這個型別的類都傳入到onStartup方法的Set<Class<?>>;為這些WebApplicationInitializer型別的類建立例項;

4)、每一個WebApplicationInitializer都呼叫自己的onStartup;



5)、相當於我們的SpringBootServletInitializer的類會被建立物件,並執行onStartup方法

6)、SpringBootServletInitializer例項執行onStartup的時候會createRootApplicationContext;建立容器

    protected WebApplicationContext createRootApplicationContext(
          ServletContext servletContext) {
        //1、建立SpringApplicationBuilder
       SpringApplicationBuilder builder = createSpringApplicationBuilder();
       StandardServletEnvironment environment = new StandardServletEnvironment();
       environment.initPropertySources(servletContext, null);
       builder.environment(environment);
       builder.main(getClass());
       ApplicationContext parent = getExistingRootWebApplicationContext(servletContext);
       if (parent != null) {
          this.logger.info("Root context already created (using as parent).");
          servletContext.setAttribute(
                WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, null);
          builder.initializers(new ParentContextApplicationContextInitializer(parent));
       }
       builder.initializers(
             new ServletContextApplicationContextInitializer(servletContext));
       builder.contextClass(AnnotationConfigEmbeddedWebApplicationContext.class);
        
        //呼叫configure方法,子類重寫了這個方法,將SpringBoot的主程式類傳入了進來
       builder = configure(builder);
        
        //使用builder建立一個Spring應用
       SpringApplication application = builder.build();
       if (application.getSources().isEmpty() && AnnotationUtils
             .findAnnotation(getClass(), Configuration.class) != null) {
          application.getSources().add(getClass());
       }
       Assert.state(!application.getSources().isEmpty(),
             "No SpringApplication sources have been defined. Either override the "
                   + "configure method or add an @Configuration annotation");
       // Ensure error pages are registered
       if (this.registerErrorPageFilter) {
          application.getSources().add(ErrorPageFilterConfiguration.class);
       }
        //啟動Spring應用
       return run(application);
    }

7)、Spring的應用就啟動並且建立IOC容器

    public ConfigurableApplicationContext run(String... args) {
       StopWatch stopWatch = new StopWatch();
       stopWatch.start();
       ConfigurableApplicationContext context = null;
       FailureAnalyzers analyzers = null;
       configureHeadlessProperty();
       SpringApplicationRunListeners listeners = getRunListeners(args);
       listeners.starting();
       try {
          ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                args);
          ConfigurableEnvironment environment = prepareEnvironment(listeners,
                applicationArguments);
          Banner printedBanner = printBanner(environment);
          context = createApplicationContext();
          analyzers = new FailureAnalyzers(context);
          prepareContext(context, environment, listeners, applicationArguments,
                printedBanner);
           
           //重新整理IOC容器
          refreshContext(context);
          afterRefresh(context, applicationArguments);
          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);
       }
    }