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

本文详细分析了SpringBoot2.1.6中,当Maven引入Tomcat依赖时的启动流程。从ServletWebServerFactoryConfiguration类开始,讨论了如何选择并初始化TomcatServletWebServerFactory,然后通过源码跟踪,从main方法开始,逐步解析到ServletWebServerApplicationContext的onRefresh方法,最后深入TomcatServletWebServerFactory的getWebServer方法,启动Tomcat服务器的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文基于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.youkuaiyun.com/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.youkuaiyun.com/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.youkuaiyun.com/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.youkuaiyun.com/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> 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菠萝科技

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值