SpringBoot嵌入式Servlet容器配置修改以及注册三大组件

SpringBoot中默认使用Tomcat作为嵌入式Servlet容器。
关于嵌入式Servlet容器,在我们曾经的传统web项目中,需要将项目打包成war包,部署在Tomcat中,并配置好Tomcat环境,将其作为容器,外部启动Tomcat就可以运行项目了。
而我们SpringBoot是无需外部启动Tomcat,使用的是自带的Tomcat。

		<!-- 引入web模块 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

当我们添加web模块的依赖时,查看依赖图
在SpringBoot2.4.0中,Tomcat使用的是9.0.39版本
在这里插入图片描述

1、如何定制和修改Servlet容器的相关配置

外部的Tomcat可以在/config的server.xml或者web.xml配置环境,而springboot中怎么配置呢?

1.修改和server有关的配置,比如端口等。
在这里插入图片描述
点进去发现里面是ServerProperties类,通过它来绑定和server有关的配置

@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {
	private Integer port; // 端口号
	...
	private final Tomcat tomcat = new Tomcat();
	...
	
	public static class Servlet {
		private String contextPath; // 访问路径
		...
	}
	...
}

所以我们可以通过 :
//通用的Servlet容器设置
server.xxx
//Tomcat的设置
server.tomcat.xxx

这样来通过在配置文件中修改配置。

2.编写一个 WebServerFactoryCustomizer 嵌入式的Servlet容器的定制器,来修改Servlet容器的配置

首先我编写了一个配置类,里面添加一个组件

@Configuration
public class MyServerConfig {
	// 配置嵌入式Servlet容器
    @Bean
    public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer() {
        return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>() {
            //定制嵌入式的Servlet容器相关规则
            @Override
            public void customize(ConfigurableWebServerFactory factory) {
                factory.setPort(8091); // 设置端口号为8091
            }
        };
    }

}

2.注册Servlet三大组件

由于SpringBoot默认是以jar包的方式启动嵌入式的Servlet容器来启动SpringBoot的web应用,没有web.xml文件。
所以在SpringBoot中通过以下三个RegistrationBean注册组件 :
ServletRegistrationBean —> servlet
FilterRegistrationBean —> filter
ServletListenerRegistrationBean —> listener

首先自己分别编写Servlet、filter、listener

public class MyServiet extends HttpServlet {
    // 处理get请求
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("Hello MyServlet");
    }
}
//-------------------------------------------------------------------

/**
 * JDK8的接口方法可以使用default修饰,可以有方法实现
 * Tomcat 9.0 使用的Servlet版本是4.0 ,所以可以直接重写doFilter
 */
public class MyFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("MyFilter");
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

//-------------------------------------------------------------------
public class MyListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("contextInitialized 初始化...web应用启动");
    }
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("contextDestroyed 销毁...当前web项目销毁");
    }
}

然后在我们的配置文件中注册三大组件,如下

@Configuration
public class MyServerConfig {

    // 注册三大组件
    @Bean
    public ServletRegistrationBean myServlet() {
        // 小tip : 不能使用@WebServlet注解,因为这个是控制器寻找Servlet,还是需要将这个写给容器
        ServletRegistrationBean<Servlet> servletServletRegistrationBean = new ServletRegistrationBean<>(new MyServiet(), "/myServlet");
        servletServletRegistrationBean.setLoadOnStartup(1); // 设置优先级
        return servletServletRegistrationBean;
    }

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

    @Bean
    public ServletListenerRegistrationBean myListener() {
        ServletListenerRegistrationBean<EventListener> registrationBean = new ServletListenerRegistrationBean<>(new MyListener());
        return registrationBean;
    }

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

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

}

曾经在SpirngMVC中,我们要在web.xml中手动配置DIspatcherServlet前端控制器,曾经的配置如下(了解)

<!-- 前端控制器(加载classpath:springmvc.xml 服务器启动创建servlet) -->
  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 配置初始化参数,创建完DispatcherServlet对象,加载springmvc.xml配置文件 -->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
    <!-- 服务器启动的时候,让DispatcherServlet对象创建 -->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <!-- 处理所有*.action的映射请求 -->
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>*.action</url-pattern>
  </servlet-mapping>

SpringBoot帮我们自动SpringMVC的时候,自动地注册SpringMVC的前端控制器DIspatcherServlet在 DispatcherServletAutoConfiguration中。

@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
public class DispatcherServletAutoConfiguration {

	...

	@Configuration(proxyBeanMethods = false)
	@Conditional(DispatcherServletRegistrationCondition.class)
	@ConditionalOnClass(ServletRegistration.class)
	@EnableConfigurationProperties(WebMvcProperties.class)
	@Import(DispatcherServletConfiguration.class)
	protected static class DispatcherServletRegistrationConfiguration {

		@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
		@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
		public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet,
				WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {
			DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,webMvcProperties.getServlet().getPath());
			//默认拦截: / 所有请求;包静态资源,但是不拦截jsp请求; /*会拦截jsp
			//可以通过server.servletPath来修改SpringMVC前端控制器默认拦截的请求路径
			registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
			registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
			multipartConfig.ifAvailable(registration::setMultipartConfig);
			return registration;
		}
	}
}

可能用图片更加清楚一点
在这里插入图片描述
如果有需要补充说明,欢迎大佬指点江山!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

舍其小伙伴

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

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

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

打赏作者

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

抵扣说明:

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

余额充值