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;
}
}
}
可能用图片更加清楚一点
如果有需要补充说明,欢迎大佬指点江山!