当前位置: 首页 > news >正文

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(返回的是一个字符串) 

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • upload-labs漏洞靶场~文件上传漏洞
  • 【优秀python案例】基于python爬虫的深圳房价数据分析与可视化实现
  • Leetcode3227. 字符串元音游戏
  • 国产版Sora复现——智谱AI开源CogVideoX-2b 本地部署复现实践教程
  • C++速学day1
  • 做不好PPT的原因
  • 左手坐标系、右手坐标系、坐标轴方向
  • thinkphp之命令执行漏洞复现
  • SpringBoot入门、进阶、强化、扩展、知识体系完善等知识点学习、性能优化、源码分析专栏分享
  • LLaMA- Adapter V2: Parameter-Efficient Visual Instruction Model
  • AI在招聘市场趋势分析中的应用
  • 完美解决pip命令版本冲突导致对应版本模块包无法安装的问题
  • PHP进阶-CentOS7部署LNMP服务架构的项目
  • Swift 析构过程
  • 初步认识vue
  • [iOS]Core Data浅析一 -- 启用Core Data
  • [Vue CLI 3] 配置解析之 css.extract
  • [译] 理解数组在 PHP 内部的实现(给PHP开发者的PHP源码-第四部分)
  • 《网管员必读——网络组建》(第2版)电子课件下载
  • 10个最佳ES6特性 ES7与ES8的特性
  • iOS帅气加载动画、通知视图、红包助手、引导页、导航栏、朋友圈、小游戏等效果源码...
  • JavaSE小实践1:Java爬取斗图网站的所有表情包
  • uva 10370 Above Average
  • ViewService——一种保证客户端与服务端同步的方法
  • 编写高质量JavaScript代码之并发
  • 给github项目添加CI badge
  • 排序算法之--选择排序
  • 前端面试之闭包
  • 如何使用Mybatis第三方插件--PageHelper实现分页操作
  • 深入浅出Node.js
  • 数组的操作
  • 微信如何实现自动跳转到用其他浏览器打开指定页面下载APP
  • 小程序、APP Store 需要的 SSL 证书是个什么东西?
  • 正则与JS中的正则
  • 智能合约开发环境搭建及Hello World合约
  • 通过调用文摘列表API获取文摘
  • ​批处理文件中的errorlevel用法
  • #前后端分离# 头条发布系统
  • (160)时序收敛--->(10)时序收敛十
  • (C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作...
  • (java)关于Thread的挂起和恢复
  • (MATLAB)第五章-矩阵运算
  • (vue)el-cascader级联选择器按勾选的顺序传值,摆脱层级约束
  • (附源码)springboot教学评价 毕业设计 641310
  • (附源码)ssm高校社团管理系统 毕业设计 234162
  • (六)激光线扫描-三维重建
  • (四)c52学习之旅-流水LED灯
  • (转)VC++中ondraw在什么时候调用的
  • *1 计算机基础和操作系统基础及几大协议
  • .NET 使用 ILMerge 合并多个程序集,避免引入额外的依赖
  • .net反混淆脱壳工具de4dot的使用
  • .NET构架之我见
  • @ModelAttribute注解使用
  • @param注解什么意思_9000字,通俗易懂的讲解下Java注解
  • [AI StoryDiffusion] 创造神奇故事,AI漫画大乱斗!