springboot2|springboot启动流程源码分析:tomcat启动原理

  • Post author:
  • Post category:其他


本文基于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> 



版权声明:本文为wabiaozia原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。