SpringBoot嵌入式Servlet容器自动配置原理

以前的web应用开发我们采取的方式是项目完成后打包成war包,然后配置tomcat启动运行项目,而Spring Boot默认使用的是嵌入式的tomcat,那我们需要如何配置嵌入式的Servlet容器呢?

定制修改Servlet容器相关配置

修改和server有关的配置

我们可以到项目的配置文件中直接对server的属性进行修改。

config

在ServerProperties中我们能够看到所有可以进行配置的属性。

context

编写一个WebServerFactoryCustomizer:web服务器工厂定制器

在Spring Boot2.0及以上版本的学习过程中,我发现了多处与之前版本不同的地方,应该算是Spring Boot开发者的优化。之后我将专门写一篇来对2.0版本进行更新的总结。先说web服务器工厂定制器,在Spring Boot2.0中已经使用WebServerFactoryCustomizer取代了EmbeddedServletContainerCustomizer,当我们需要定制Servlet容器的时候,我们采取这样的方式。

		//配置嵌入式的Servlet容器
    @Bean
    public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer(){
        return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>(){

            //定制嵌入式的Servlet容器相关的规则
            @Override
            public void customize(ConfigurableWebServerFactory factory) {
                factory.setPort(8083);
            }
        };
    }

注册Servlet三大组件(Servlet、Filter、Listener)

以前的Spring项目注册三大组件是在项目下的webapp/WEB-INF/web.xml文件中进行配置,由于Spring Boot是以jar包的方式启动嵌入式的Servlet容器来启动web应用,它并没有web.xml文件,我们注册三大组件采用如下方式:

		//注册三大组件Servlet
    @Bean
    public ServletRegistrationBean myServlet(){
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(new MyServlet(),"/myServlet");
        registrationBean.setLoadOnStartup(1);
        return registrationBean;

    }

    //注册Filter
    @Bean
    public FilterRegistrationBean myFilter(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>();
        filterRegistrationBean.setFilter(new MyFilter());
        filterRegistrationBean.setUrlPatterns(Arrays.asList("/hello","/myServlet"));
        return filterRegistrationBean;
    }

    //注册Listener
    @Bean
    public ServletListenerRegistrationBean myListener(){
        ServletListenerRegistrationBean<MyListener> servletListenerRegistrationBean = new ServletListenerRegistrationBean<>(new MyListener());
        return servletListenerRegistrationBean;
    }

嵌入式Servlet容器自动配置原理

整个Spring Boot最核心的部分都在它的自动配置原理中,Spring Boot支持三种嵌入式Servlet容器:tomcat、jetty、undertow。在这里就不对切换做过多说明,我们主要研究自动配置原理。

ServletWebServerFactoryConfiguration:Servlet容器工厂的配置

在这边我们又发现了2.0版本中的更新,它将原来放在EmbeddedServletContainerAutoConfiguration中对TomcatServletWebServerFactory、JettyServletWebServerFactory、UndertowServletWebServerFactory的配置放到了ServletWebServerFactoryConfiguration中,它会使用@ConditionalOnClass注解先判断是否已经有了Servlet以及其他的class,如果没有,@Configuration注解就会进行配置,我们进入到Spring Boot源码中进行查看。

@Configuration
class ServletWebServerFactoryConfiguration {

	@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();
		}

	}

	/**
	 * 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();
		}

	}

	/**
	 * Nested configuration if Undertow is being used.
	 */
	@Configuration
	@ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
	@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
	public static class EmbeddedUndertow {

		@Bean
		public UndertowServletWebServerFactory undertowServletWebServerFactory() {
			return new UndertowServletWebServerFactory();
		}

	}

}

以TomcatServletWebServerFactory为例

public class TomcatServletWebServerFactory extends AbstractServletWebServerFactory
		implements ConfigurableTomcatWebServerFactory, ResourceLoaderAware {
			...
		}

我们可以看到TomcatServletWebServerFactory实现了ConfigurableTomcatWebServerFactory接口,我们再进入到ConfigurableTomcatWebServerFactory中查看,能够发现它继承了ConfigurableWebServerFactory接口,并且JettyServletWebServerFactory、UndertowServletWebServerFactory都实现了ConfigurableWebServerFactory接口。

public interface ConfigurableTomcatWebServerFactory extends ConfigurableWebServerFactory {
	...
}

public interface ConfigurableJettyWebServerFactory extends ConfigurableWebServerFactory {
  ...
}

public interface ConfigurableUndertowWebServerFactory
		extends ConfigurableWebServerFactory {
  ...
}

我们能够看到getWebServer()方法中,创建了一个tomcat对象,并且最后将tomcat返回,启动了tomcat服务器。

	@Override
	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);
	}

嵌入式容器配置修改的生效

WebServerFactoryCustomizer:定制器帮助修改了Servlet容器的配置。修改的原理:容器中的WebServerFactoryCustomizerBeanPostProcessor后置处理器生效。

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName)
			throws BeansException {
    //如果当前初始化的是一个WebServerFactory类型的组件
		if (bean instanceof WebServerFactory) {
			postProcessBeforeInitialization((WebServerFactory) bean);
		}
		return bean;
	}

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

	@SuppressWarnings("unchecked")
	private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
		LambdaSafe
				.callbacks(WebServerFactoryCustomizer.class, getCustomizers(),
						webServerFactory)
				.withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)
				.invoke((customizer) -> customizer.customize(webServerFactory));
	}

	private Collection<WebServerFactoryCustomizer<?>> getCustomizers() {
		if (this.customizers == null) {
			// Look up does not include the parent context
			this.customizers = new ArrayList<>(getWebServerFactoryCustomizerBeans());
			this.customizers.sort(AnnotationAwareOrderComparator.INSTANCE);
			this.customizers = Collections.unmodifiableList(this.customizers);
		}
		return this.customizers;
	}

配置原理总结

  • Spring Boot根据导入的情况,给容器中添加相应的如TomcatServletWebServerFactory。
  • 容器中某个组件要创建对象就会触发WebServerFactoryCustomizerBeanPostProcessor,只要是嵌入式的Servlet容器工厂,后置处理器就会工作。
  • WebServerFactoryCustomizerBeanPostProcessor后置处理器,从容器中获取所有的WebServerFactoryCustomizer,调用定制器的定制方法。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

当一艘船沉入海底8

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

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

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

打赏作者

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

抵扣说明:

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

余额充值