以前的web应用开发我们采取的方式是项目完成后打包成war包,然后配置tomcat启动运行项目,而Spring Boot默认使用的是嵌入式的tomcat,那我们需要如何配置嵌入式的Servlet容器呢?
定制修改Servlet容器相关配置 修改和server有关的配置 我们可以到项目的配置文件中直接对server的属性进行修改。
在ServerProperties中我们能够看到所有可以进行配置的属性。
编写一个WebServerFactoryCustomizer:web服务器工厂定制器 在Spring Boot2.0及以上版本的学习过程中,我发现了多处与之前版本不同的地方,应该算是Spring Boot开发者的优化。之后我将专门写一篇来对2.0版本进行更新的总结。先说web服务器工厂定制器,在Spring Boot2.0中已经使用WebServerFactoryCustomizer取代了EmbeddedServletContainerCustomizer,当我们需要定制Servlet容器的时候,我们采取这样的方式。
1 2 3 4 5 6 7 8 9 10 11 12 @Bean public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer () { return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>(){ @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文件,我们注册三大组件采用如下方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @Bean public ServletRegistrationBean myServlet () { ServletRegistrationBean registrationBean = new ServletRegistrationBean(new MyServlet(),"/myServlet" ); registrationBean.setLoadOnStartup(1 ); return registrationBean; } @Bean public FilterRegistrationBean myFilter () { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>(); filterRegistrationBean.setFilter(new MyFilter()); filterRegistrationBean.setUrlPatterns(Arrays.asList("/hello" ,"/myServlet" )); return filterRegistrationBean; } @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源码中进行查看。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 @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(); } } @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(); } } @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为例 1 2 3 4 public class TomcatServletWebServerFactory extends AbstractServletWebServerFactory implements ConfigurableTomcatWebServerFactory , ResourceLoaderAware { ... }
我们可以看到TomcatServletWebServerFactory实现了ConfigurableTomcatWebServerFactory接口,我们再进入到ConfigurableTomcatWebServerFactory中查看,能够发现它继承了ConfigurableWebServerFactory接口,并且JettyServletWebServerFactory、UndertowServletWebServerFactory都实现了ConfigurableWebServerFactory接口。
1 2 3 4 5 6 7 8 9 10 11 12 public interface ConfigurableTomcatWebServerFactory extends ConfigurableWebServerFactory { ... } public interface ConfigurableJettyWebServerFactory extends ConfigurableWebServerFactory { ... } public interface ConfigurableUndertowWebServerFactory extends ConfigurableWebServerFactory { ... }
我们能够看到getWebServer()方法中,创建了一个tomcat对象,并且最后将tomcat返回,启动了tomcat服务器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @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后置处理器生效。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 @Override public Object postProcessBeforeInitialization (Object bean, String beanName) throws BeansException { 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 ) { 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,调用定制器的定制方法。