您的位置:首页 > 汽车 > 时评 > SpringBoot 集成原生 Servlet、Filter、Listener

SpringBoot 集成原生 Servlet、Filter、Listener

2024/11/16 8:21:09 来源:https://blog.csdn.net/qq_38257958/article/details/140845157  浏览:    关键词:SpringBoot 集成原生 Servlet、Filter、Listener

注解方式集成 Servlet、Filter、Listener

启动类添加 @ServletComponentScan 注解
@SpringBootApplication
@ServletComponentScan
public class BlogApplication {public static void main(String[] args) {SpringApplication.run(BlogApplication.class);}
}
创建 Servlet (类上添加 @WebServlet 注解)
@Slf4j
@WebServlet(urlPatterns = {"/native_servlet"})
public class MyServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String message = "MyServlet doGet";log.info(message);response.setContentType("text/html");PrintWriter out = response.getWriter();out.println("<html><body>");out.println("<h1>" + message + "</h1>");out.println("</body></html>");}
}
创建 Filter (类上添加 @WebFilter 注解)
@Slf4j
@WebFilter
public class MyFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {log.info("MyFilter init");}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {log.info("MyFilter doFilter");chain.doFilter(request, response);}@Overridepublic void destroy() {log.info("MyFilter destroy");}
}
创建 Listener(类上添加 @WebListener 注解)
@Slf4j
@WebListener
public class MyListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent sce) {log.info("MyListener contextInitialized");ServletContextListener.super.contextInitialized(sce);}@Overridepublic void contextDestroyed(ServletContextEvent sce) {log.info("MyListener contextDestroyed");ServletContextListener.super.contextDestroyed(sce);}
}
启动项目,访问链接:http://localhost:8080/native_servlet

Servlet、Filter、Listener 都生效了

使用 RegistrationBean 集成 Servlet、Filter、Listener

将方式1类上的相关注解(@ServletComponentScan@WebServlet@WebFilter@WebListener)都注释掉

创建配置类 RegistrationConfig
@Configuration
public class RegistrationConfig {@Beanpublic ServletRegistrationBean<MyServlet> myServlet() {MyServlet myServlet = new MyServlet();return new ServletRegistrationBean<>(myServlet, "/registration_servlet");}@Beanpublic FilterRegistrationBean<MyFilter> myFilter() {MyFilter myFilter = new MyFilter();FilterRegistrationBean<MyFilter> filterRegistrationBean = new FilterRegistrationBean<>(myFilter);filterRegistrationBean.setUrlPatterns(Arrays.asList("/registration_servlet", "/css/*", "/js/*"));return filterRegistrationBean;}@Beanpublic ServletListenerRegistrationBean<MyListener> myListener() {MyListener myListener = new MyListener();return new ServletListenerRegistrationBean<>(myListener);}
}
启动项目,访问链接:http://localhost:8080/registration_servlet

Servlet、Filter、Listener 都生效了

Interceptor 是否对原生 Servlet 生效?

创建拦截器 FirstInterceptor
@Slf4j
public class FirstInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {log.info("FirstInterceptor preHandle");return HandlerInterceptor.super.preHandle(request, response, handler);}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {log.info("FirstInterceptor postHandle");HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {log.info("FirstInterceptor afterCompletion");HandlerInterceptor.super.afterCompletion(request, response, handler, ex);}
}
创建配置文件 InterceptorConfig
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new FirstInterceptor());}
}
创建 DispatcherServletController
@RestController
@RequestMapping
public class DispatcherServletController {@RequestMapping("/dispatcher_servlet")public String dispatcherServlet() {return "dispatcher servlet";}}
访问链接:http://localhost:8080/dispatcher_servlet

FirstInterceptor 生效

再次访问链接:http://localhost:8080/registration_servlet

 FirstInterceptor 对原生 servlet 不生效

Servlet 路径匹配

默认情况下,SpringBoot 只有一个 Servlet (DispatcherServlet),当我们配置了原生的 servlet ,web 容器中就存在两个 Servlet,web 容器根据最佳匹配原则,映射到指定的 Servlet 上

如果 MyServlet 的的匹配路径也是 / ,会发生什么现象?
将 MyServlet 的拦截路径改成 /

在 DispatcherServletController 中添加接口

访问链接 : http://localhost:8080/

通过响应我们可以知道,选择的是 MyServlet(返回的是一个 html)

为什么选择MyServlet?
ServletWebServerApplicationContext#selfInitialize

getServletContextInitializerBeans 的返回值中 MyServlet 的优先级最高且满足最佳匹配,所以会选择 MyServlet

getServletContextInitializerBeans 方法是如何排序的

getServletContextInitializerBeans 方法是通过 AnnotationAwareOrderComparator 排序的,规则如下:

  1. ServletContextInitializer 实现类是否继承 PriorityOrdered 接口,如果都继承 PriorityOrdered 接口,比较 getOrder 方法返回的值,值越小,优先级越高
  2. ServletContextInitializer 实现类是否继承 Ordered 接口,如果都继承 Ordered 接口,比较 getOrder 方法返回的值,值越小,优先级越高
  3. ServletContextInitializer 实现类所属class上是否存在 @Order 注解,如果存在,比较注解设置的值,值越小,优先级越高
  4. ServletContextInitializer 实现类所属class上是否存在 @Priority 注解,如果存在,比较注解设置的值,值越小,优先级越高

DispatcherServletRegistrationBean 继承 RegistrationBean ,RegistrationBean 的 getOrder 方法返回值是 Ordered.LOWEST_PRECEDENCE,对于同样继承 RegistrationBean 的 ServletRegistrationBean 优先级一致,但是 ServletRegistrationBean 解析时机稍后,所以默认情况下优先级更高。

修改 DispatcherServletRegistrationBean 优先级

创建 FirstPostProcessor

@Component
public class FirstPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if ("dispatcherServletRegistration".equals(beanName) && (bean instanceof DispatcherServletRegistrationBean)) {DispatcherServletRegistrationBean dispatcherServletRegistrationBean = (DispatcherServletRegistrationBean) bean;dispatcherServletRegistrationBean.setOrder(-1);}return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);}
}

 访问链接 : http://localhost:8080/

通过响应我们可以知道,选择的是 DispatcherServlet(返回的是一个字符串) 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com