Springboot之整合tomcat容器过程

本文详细解析了SpringBoot如何创建并启动Tomcat容器,以及如何将DispatcherServlet注册到Tomcat中。

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

前言

  Tomcat容器最主要作用就是监听网络请求,并将请求封装成request和response对象最终交给Servlet去执行,而我们spring项目中用来供servlet调用的业务代码的入口一般就是Spring管理的Controller。而Springboot整合tomcat的话,就需要提供一个Servlet的标准实现,并将这个Servlet注册到Tomcat容器里,并且在Servlet处理请求时,能调用Spring所管理的Controller进而使用Spring容器的所有资源。所以这里最主要的两个问题是:
1、Springboot是怎么创建和启动Tomcat的?
2、Springboot怎么将DispatcherServlet注册到tomcat容器中?

在分析问题前,先看下Tomcat的架构图,有助于后面看代码:

这里可以看出一个Tomcat就是一个Server,一个Server下会有多个Service,Service只负责封装多个Connector和一个Container(Service本身不是容器,可以看做只是用来包装Connector和Container的壳,不负责具体功能),而Container(也叫engine)下又有多个Host,每个Host下对应多个Context,Context下才是我们的Servlet,Tomcat为了使整个架构灵活,所以抽象出这么多层,每层之间都可以根据不同的维度产生一对多个配置。对应到Tomcat类:

再看下主要容器的类图,这里所有的容器都继承自LifecycleBase抽象类,这个类抽象了控制生命周期的方法,比如init、start、stop、destory方法,而负责处理请求的四个容器又都继承了ContainerBase抽象类,这个抽象类最主要是抽象了pipeline(可以理解为一个调用链,一个接下一个的处理)来处理请求的逻辑,所以请求到达这四个容器后,实际是通过pipeline来处理请求,类图如下:

一、Springboot是怎么创建和启动Tomcat的?

  Springboot启动的主要方法是AbstractApplicationContext类的refresh方法,而springboot启动Tomcat容器的逻辑在ServletWebServerApplicationContext类的onRefresh方法里,这里从这个方法的代码开始debug:


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

private void createWebServer() {
   
		WebServer webServer = this.webServer;
		ServletContext servletContext = getServletContext();
		if (webServer == null && servletContext == null) {
   
		// 1.0
			ServletWebServerFactory factory = getWebServerFactory();
			// 2.0
			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();
	}

1.0源码分析

/**
	 * Returns the {@link ServletWebServerFactory} that should be used to create the
	 * embedded {@link WebServer}. By default this method searches for a suitable bean in
	 * the context itself.
	 * @return a {@link ServletWebServerFactory} (never {@code null})
	 */
	protected ServletWebServerFactory getWebServerFactory() {
   
		// Use bean names so that we don't consider the hierarchy
		String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
		if (beanNames.length == 0) {
   
			throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing "
					+ "ServletWebServerFactory bean.");
		}
		if (beanNames.length > 1) {
   
			throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple "
					+ "ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));
		}
		return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
	}

这部分就是获取web容器的工厂类,这个工厂类是一个接口,先看下这个ServletWebServerFactory接口的实现类图:

可以看到有tomcat、Jetty、Undertow三种,那么这里get出来的具体是哪种?这个逻辑就在org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration这个类里,这个类是springboot容器初始化时自动转载进容器的,springboot自动加载的原理在这里,在spring-boot-autoconfigure包的spring.factories里配置了所有需要自动装载进容器的类,如下图:

这个类的作用就是告诉spring容器如何加载容器,这里先看下ServletWebServerFactoryAutoConfigurat

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值