SpringBoot嵌入式Servlet的自动配置原理

一、1.x 版本的嵌入式Servlet自动配置原理

【1】嵌入式Servlet容器的自动配置类(EmbeddedServletContainerAutoConfiguration):

@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication  //表示在web应用环境下该自动配置才生效
//作用:给容器中导入一些组件
//导入了(后置处理器)EmbeddedServletContainerCustomizerBeanPostProcessor组件。作用:在Bean初始化前后(刚创建完前后还未属性赋值)执行前置/后置的逻辑
@Import(BeanPostProcessorsRegistrar.class)
public class EmbeddedServletContainerAutoConfiguration {
   
    @Configuration
    @ConditionalOnClass({ Servlet.class, Tomcat.class })//判断当前是否引入了tomcat依赖
    //判断当前容器没有用户自己定义的嵌入式servlet容器工厂(EmbeddedServletContainerFactory)。作用:servlet容器工厂用来创建嵌入式的servlet容器
    @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)

	public static class EmbeddedTomcat {
		@Bean
		public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
			return new TomcatEmbeddedServletContainerFactory();
		}
	}
	
    //Jetty

    //Undertow
}	

【2】EmbeddedServletContainerFactory 嵌入式servlet容器工厂

public interface EmbeddedServletContainerFactory {

    //获取嵌入式的servlet容器
    EmbeddedServletContainer getEmbeddedServletContainer(ServletContextInitializer... var1);
}
(1)EmbeddedServletContainerFactory 中的三种嵌入式的servlet容器工厂:

在这里插入图片描述

(2)对应的三种嵌入式servlet容器:

在这里插入图片描述

【3】以 TomcatEmbeddedServletContainerFactory 为例

@Override
public EmbeddedServletContainer getEmbeddedServletContainer(
	ServletContextInitializer... initializers) {
	//1.创建一个Tomcat
	Tomcat tomcat = new Tomcat();
	
	//2.配置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);
	
	//3.将配置好的Tomcat放到servlet容器中,然后返回一个EmbeddedServletContainer,启动Tomcat服务器
	return getTomcatEmbeddedServletContainer(tomcat);
}
protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(
 Tomcat tomcat) {
	return new TomcatEmbeddedServletContainer(tomcat, getPort() >= 0);
}

tomcat, getPort() >= 0成立,tomcat自动启动。

public TomcatEmbeddedServletContainer(Tomcat tomcat, boolean autoStart) {
		Assert.notNull(tomcat, "Tomcat Server must not be null");
		this.tomcat = tomcat;
		this.autoStart = autoStart;
		initialize();
	}
private void initialize() throws EmbeddedServletContainerException {
		TomcatEmbeddedServletContainer.logger
				.info("Tomcat initialized with port(s): " + getPortsDescription(false));
		synchronized (this.monitor) {
			try {
				addInstanceIdToEngineName();
				try {
					// Remove service connectors to that protocol binding doesn't happen
					// yet
					removeServiceConnectors();

					// Start the server to trigger initialization listeners
					// 启动Tomcat服务器
					this.tomcat.start();

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

					Context context = findContext();
					try {
						ContextBindings.bindClassLoader(context, getNamingToken(context),
								getClass().getClassLoader());
					}
					catch (NamingException ex) {
						// Naming is not enabled. Continue
					}

					// Unlike Jetty, all Tomcat threads are daemon threads. We create a
					// blocking non-daemon to stop immediate shutdown
					startDaemonAwaitThread();
				}
				catch (Exception ex) {
					containerCounter.decrementAndGet();
					throw ex;
				}
			}
			catch (Exception ex) {
				throw new EmbeddedServletContainerException(
						"Unable to start embedded Tomcat", ex);
			}
		}
	}
(1)对嵌入式容器的配置是如何生效的?
  • 修改ServerProperties里的属性。
  • 自定义一个嵌入式servlet容器定制器EmbeddedServletContainerCustomizer
(2)EmbeddedServletContainerCustomizerservlet容器定制器如何帮助我们修改的servlet容器的配置?

① 容器中导入了EmbeddedServletContainerCustomizerBeanPostProcessor(后置处理器)

//在初始化之前(对象创建好但是还未赋值)
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
	throws BeansException {
	//如果当前初始化的是ConfigurableEmbeddedServletContainer类型的组件
	if (bean instanceof ConfigurableEmbeddedServletContainer) {
			
	//就调用postProcessBeforeInitialization方法
	postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean);
	}
	return bean;
 }

private void postProcessBeforeInitialization(
	ConfigurableEmbeddedServletContainer bean) {
	//获取所有的定制器,调用每一个定制器的customize方法来给servlet容器进行属性赋值
	for (EmbeddedServletContainerCustomizer customizer : getCustomizers()) {
		customizer.customize(bean);
	}
}

//核心就是利用IOC容器获取EmbeddedServletContainerCustomizer类型的组件
//结论:如果我们想要定制servlet容器,就要给容器添加EmbeddedServletContainerCustomizer类型的组件
private Collection<EmbeddedServletContainerCustomizer> getCustomizers() {
	if (this.customizers == null) {
	// Look up does not include the parent context
	this.customizers = new ArrayList<EmbeddedServletContainerCustomizer>(
					this.beanFactory
							.getBeansOfType(EmbeddedServletContainerCustomizer.class,
									false, false)
							.values());
	Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE);
	this.customizers = Collections.unmodifiableList(this.customizers);
	}
	return this.customizers;
}

在容器初始化之后进行配置的修改:

@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
			throws BeansException {
	return bean;
}

② ServerProperties也是EmbeddedServletContainerCustomizer
在这里插入图片描述

【4】总结步骤

  • SpringBoot根据导入的依赖情况,给容器中添加相应的 EmbeddedServletContainerFactory【TomcatEmbeddedServletContainerFactory】
  • 容器中某个组件要创建对象就会惊动后置处理器EmbeddedServletContainerCustomizerBeanPostProcessor。只要是嵌入式的Servlet容器工厂,后置处理器就工作;
  • 后置处理器从容器中获取所有的EmbeddedServletContainerCustomizer,调用定制器的定制方法

二、2.x 的嵌入式Servlet容器自动配置原理

参考链接:https://www.jianshu.com/p/017a7f40efff

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值