SpringBoot默认使用Tomcat作为嵌入式的Servlet容器
1、如何定制和修改Servlet容器的相关配置
1、修改和server有关的配置
在全局配置文件中修改默认的server的属性
2、编写一个EmbeddedServletContainerCustomizer:嵌入式的Servlet容器的定制器
@Bean public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer(){ return new EmbeddedServletContainerCustomizer() { //定制嵌入式的Servlet容器的配置 @Override public void customize(ConfigurableEmbeddedServletContainer configurableEmbeddedServletContainer) { //设置端口号 configurableEmbeddedServletContainer.setPort(8083); } }; }
2、注册Servlet三大组件【Servlet、Filter、Listener】
由于SpringBoot默认是以jar包的方式启动嵌入式的Servlet容器来启动SpringBoot的web应用,没有web.xml文件
注册三大组件用以下方式
①、注册Servlet使用:ServletRegistrationBean
ServletRegistrationBean的一个有参构造器,传入一个servlet和拦截的路径
自定义的一个servlet:
public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("Hello MyServlet"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } }
注册 servlet:
//注册Servlet @Bean public ServletRegistrationBean servletRegistrationBean(){ ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new MyServlet(),"/myServlet"); return servletRegistrationBean; }
访问路径,查看servlet是否注册成功
②、注册Filter使用:FilterRegistrationBean
自定义一个Filter:
public class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("MyFilter执行"); filterChain.doFilter(servletRequest,servletResponse); } @Override public void destroy() { } }
注册Filter:
//注册Filter @Bean public FilterRegistrationBean filterRegistrationBean(){ FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); //设置Filter filterRegistrationBean.setFilter(new MyFilter()); //拦截/myServlet请求 filterRegistrationBean.setUrlPatterns(Arrays.asList("/myServlet")); return filterRegistrationBean; }
发送请求,查看filter是否注册成功:
③、注册Listener使用:ServletListenerRegistrationBean
自定义一注册Listener:
public class MyListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent servletContextEvent) { System.out.println("web应用启动"); } @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { System.out.println("Web项目销毁"); } }
注册Listener:
//注册Listener @Bean public ServletListenerRegistrationBean servletListenerRegistrationBean(){ ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>(new MyListener()); return registrationBean; }
测试Listener是否注册成功:
启动:
销毁:
3、替换为其他嵌入式Servlet容器
Tomcat(默认使用)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> 引入web模块默认就是使用嵌入式的Tomcat作为Servlet容器; </dependency>
切换为Jetty:
<!-- 引入web模块 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <artifactId>spring-boot-starter-tomcat</artifactId> <groupId>org.springframework.boot</groupId> </exclusion> </exclusions> </dependency> <!--引入其他的Servlet容器--> <dependency> <artifactId>spring-boot-starter-jetty</artifactId> <groupId>org.springframework.boot</groupId> </dependency>
切换为Undertow:
<!-- 引入web模块 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <artifactId>spring-boot-starter-tomcat</artifactId> <groupId>org.springframework.boot</groupId> </exclusion> </exclusions> </dependency> <!--引入其他的Servlet容器--> <dependency> <artifactId>spring-boot-starter-undertow</artifactId> <groupId>org.springframework.boot</groupId> </dependency>
4、嵌入式Servlet容器自动配置原理
EmbeddedServletContainerAutoConfiguration:嵌入式的Servlet容器自动配置
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) @Configuration @ConditionalOnWebApplication @Import(BeanPostProcessorsRegistrar.class) //导入BeanPostProcessorsRegistrar:Spring注解版,给容器中导入一些组件 //导入了EmbeddedServletContainerCustomizerBeanPostProcessor: //后置处理器:bean初始化前后(创建完对象,还没赋值赋值)执行初始化工作 public class EmbeddedServletContainerAutoConfiguration { @Configuration @ConditionalOnClass({ Servlet.class, Tomcat.class })//判断当前是否引入了Tomcat依赖 //判断当前容器没有用户自己定义EmbeddedServletContainerFactory:嵌入式的Servlet容器工厂 //作用:创建嵌入式的Servlet容器 @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT) public static class EmbeddedTomcat { @Bean public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() { return new TomcatEmbeddedServletContainerFactory(); } } /** * Nested configuration if Jetty is being used. */ @Configuration @ConditionalOnClass({ Servlet.class, Server.class, Loader.class, WebAppContext.class }) @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT) public static class EmbeddedJetty { @Bean public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory() { return new JettyEmbeddedServletContainerFactory(); } } /** * Nested configuration if Undertow is being used. */ @Configuration @ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class }) @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT) public static class EmbeddedUndertow { @Bean public UndertowEmbeddedServletContainerFactory undertowEmbeddedServletContainerFactory() { return new UndertowEmbeddedServletContainerFactory(); } }
1)、EmbeddedServletContainerFactory(嵌入式Servlet容器工厂)
public interface EmbeddedServletContainerFactory { //获取嵌入式的Servlet容器 EmbeddedServletContainer getEmbeddedServletContainer( ServletContextInitializer... initializers); }
继承树:
SpringBoot提供了三个Servlet容器,Tomcat、Undertow、Jetty
2)、EmbeddedServletContainer:(嵌入式的Servlet容器)
继承树:
3)、以TomcatEmbeddedServletContainerFactory为例
@Override public EmbeddedServletContainer getEmbeddedServletContainer( ServletContextInitializer... initializers) { //创建一个Tomcat Tomcat tomcat = new Tomcat(); //配置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); //将配置好的Tomcat传入进去,返回一个EmbeddedServletContainer;并且启动Tomcat服务器 return getTomcatEmbeddedServletContainer(tomcat); }
5、我们对嵌入式容器的配置修改是怎么生效的
给容器中导入了EmbeddedServletContainerCustomizerBeanPostProcessor :
EmbeddedServletContainerCustomizerBeanPostProcessor(后置处理器):
在初始化之前调用了方法,获取了所有的EmbeddedServletContainerCustomizer 定制器,给Servlet容器赋值
//初始化之前 @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { //如果当前初始化的是一个ConfigurableEmbeddedServletContainer类型的组件 if (bean instanceof ConfigurableEmbeddedServletContainer) { // postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean); } return bean; } private void postProcessBeforeInitialization( ConfigurableEmbeddedServletContainer bean) { //获取所有的定制器,调用每一个定制器的customize方法来给Servlet容器进行属性赋值; for (EmbeddedServletContainerCustomizer customizer : getCustomizers()) { customizer.customize(bean); } } private Collection<EmbeddedServletContainerCustomizer> getCustomizers() { if (this.customizers == null) { // Look up does not include the parent context this.customizers = new ArrayList<EmbeddedServletContainerCustomizer>( this.beanFactory //从容器中获取所有这个类型的组件:EmbeddedServletContainerCustomizer //定制Servlet容器,给容器中可以添加一个EmbeddedServletContainerCustomizer类型的组件 .getBeansOfType(EmbeddedServletContainerCustomizer.class, false, false) .values()); Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE); this.customizers = Collections.unmodifiableList(this.customizers); } return this.customizers; } ServerProperties也是定制器
步骤:
1)、SpringBoot根据导入的依赖情况,给容器中添加相应的EmbeddedServletContainerFactory【TomcatEmbeddedServletContainerFactory】
2)、容器中某个组件要创建对象就会惊动后置处理器,EmbeddedServletContainerCustomizerBeanPostProcessor
只要是嵌入式的Servlet容器工厂,后置处理器就工作
3)、后置处理器,从容器中获取所有的EmbeddedServletContainerCustomizer,调用定制器的定制方法