springboot2|springboot啓動流程源碼分析:tomcat啓動原理

本文基於springboot2.1.6

1 當maven引入tomcat的jar依賴時

        <dependency>
		    <groupId>org.springframework.boot</groupId>
		    <artifactId>spring-boot-starter-tomcat</artifactId>
		    <scope>provided</scope>
		</dependency>

1.1 

ServletWebServerFactoryConfiguration類中,TomcatServletWebServerFactory 會被作爲bean被spring管理起來。

根據註解@ConditionalOnClass。。條件,因爲沒有引入jetty相關的jar,spring中不會有JettyServletWebServerFactory這個bean。

@Configuration
	@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
	@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
	public static class EmbeddedTomcat {

		@Bean
		public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
			return new TomcatServletWebServerFactory();
//轉載請標明鏈接:https://blog.csdn.net/wabiaozia/article/details/95886191​​​​​​​
		}

	}

	/**
	 * Nested configuration if Jetty is being used.
	 */
	@Configuration
	@ConditionalOnClass({ Servlet.class, Server.class, Loader.class, WebAppContext.class })
	@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
	public static class EmbeddedJetty {

		@Bean
		public JettyServletWebServerFactory JettyServletWebServerFactory() {
			return new JettyServletWebServerFactory();
		}

	}

1.2

ServletWebServerApplicationContext類在使用getWebServerFactory方法獲得servlet容器時

String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);

返回對於指定類型(ServletWebServerFactory)Bean(包括子類)的所有名字。

ServletWebServerFactory的子類:JettyServletWebServerFactory,TomcatServletWebServerFactory,UndertowServletWebServerFactory,但是只引入了tomcat的jar,所以只能獲得TomcatServletWebServerFactory

2 源碼分析

2.1 首先從main函數開始

//main 函數
@SpringBootApplication
public class Demo1Application {

	public static void main(String[] args) {
		SpringApplication.run(Demo1Application.class, args);
	}

}

//點擊run
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
		return run(new Class<?>[] { primarySource }, args);
	}
//繼續點擊run
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
		return new SpringApplication(primarySources).run(args);
	}
//run
public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
			//略。。。。。
			refreshContext(context);//點擊進入。。。。。。。。。。。
			afterRefresh(context, applicationArguments);
			//略。。。。
		return context;
	}

2.2 點擊refreshContext(context);方法

點擊-->refresh(context);-->((AbstractApplicationContext) applicationContext).refresh();-->進入類AbstractApplicationContext的refresh方法

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				//略。。。。
//轉載請標明鏈接:https://blog.csdn.net/wabiaozia/article/details/95886191​​​​​​​
				onRefresh();//點擊進入
                //略

				
		}
	}

2.3 進入類ServletWebServerApplicationContext的onRefresh()方法:

@Override
	protected void onRefresh() {
		super.onRefresh();
		try {
			createWebServer();//點擊進入。。。。。。
		}
		catch (Throwable ex) {
			throw new ApplicationContextException("Unable to start web server", ex);
		}
	}

//點擊createWebServer()方法
private void createWebServer() {
		WebServer webServer = this.webServer;
		ServletContext servletContext = getServletContext();
		if (webServer == null && servletContext == null) {
            //點擊進入
			ServletWebServerFactory factory = getWebServerFactory();
//點擊進入
			this.webServer = factory.getWebServer(getSelfInitializer());
		}
		else if (servletContext != null) {
			try {
				getSelfInitializer().onStartup(servletContext);
			}
			catch (ServletException ex) {
				throw new ApplicationContextException("Cannot initialize servlet context", ex);
			}
		}
		initPropertySources();
	}

2.4 createWebServer()方法裏

            //2.4.1 點擊進入
            ServletWebServerFactory factory = getWebServerFactory();
          //2.4.2點擊進入
            this.webServer = factory.getWebServer(getSelfInitializer());

2.4.1 getWebServerFactory() 根據上文1.1裏結論會返回TomcatServletWebServerFactory。所以2.4.2的factory.getWebServer(getSelfInitializer())中的factory是指TomcatServletWebServerFactory,點擊進入實現類TomcatServletWebServerFactory的getWebServer(getSelfInitializer())方法。

	public WebServer getWebServer(ServletContextInitializer... initializers) {
		Tomcat tomcat = new Tomcat();
		File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
		tomcat.setBaseDir(baseDir.getAbsolutePath());
		Connector connector = new Connector(this.protocol);
		tomcat.getService().addConnector(connector);
		customizeConnector(connector);
		tomcat.setConnector(connector);
		tomcat.getHost().setAutoDeploy(false);
		configureEngine(tomcat.getEngine());
		for (Connector additionalConnector : this.additionalTomcatConnectors) {
			tomcat.getService().addConnector(additionalConnector);
		}
		prepareContext(tomcat.getHost(), initializers);
		return getTomcatWebServer(tomcat);//點擊進入。。。。。。。。
	}
//點擊進入getTomcatWebServer(tomcat)
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
		return new TomcatWebServer(tomcat, getPort() >= 0);//點擊進入
	}
//點擊new TomcatWebServer 
public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
		Assert.notNull(tomcat, "Tomcat Server must not be null");
		this.tomcat = tomcat;
		this.autoStart = autoStart;
		initialize();//點擊進入
	}
//點擊進入
private void initialize() throws WebServerException {
		logger.info("Tomcat initialized with port(s): " + getPortsDescription(false));
		synchronized (this.monitor) {
			try {
				
				// 略。。。。。。。
//轉載請標明鏈接:https://blog.csdn.net/wabiaozia/article/details/95886191​​​​​​​
				this.tomcat.start();//。。。。啓動tomcat

				// We can re-throw failure exception directly in the main thread
				rethrowDeferredStartupExceptions();

				try {
					ContextBindings.bindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
				}
				//略。。。。。。。。。。。。。。
		}
	}

2.5 見源碼this.tomcat.start();這行,啓動tomcat

3 至此已分析完成

轉載請標明鏈接:https://blog.csdn.net/wabiaozia/article/details/95886191

4 如果使用jetty要注意排除tomcat

<dependency>  
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-starter-web</artifactId>  
            <!-- SpringBoot默認使用tomcat ,若使用Jetty,要在spring-boot-starter-web排除spring-boot-starter-tomcat--> 
            <exclusions>  
                <exclusion>  
                    <groupId>org.springframework.boot</groupId>  
                    <artifactId>spring-boot-starter-tomcat</artifactId>  
                </exclusion>  
            </exclusions>  
        </dependency>  
<dependency>  
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-starter-jetty</artifactId>  
        </dependency> 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章