SpringBoot之Interceptor,Filter,listener

110 阅读5分钟

「这是我参与2022首次更文挑战的第17天,活动详情查看:2022首次更文挑战

拦截器

Interceptor 在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。比如日志,安全等。一般拦截器方法都是通过动态代理的方式实现。可以通过它来进行权限验证,或者判断用户是否登陆,或者是像12306 判断当前时间是否是购票时间。

新建一个RestInterceptor


@Slf4j
public class RestInterceptor extends HandlerInterceptorAdapter {

    private static final String START_TIME = "requestStartTime";

  //preHandle在业务处理器处理请求之前被调用。预处理,可以进行编码、安全控制等处理;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //根据请求信息判断是否需要拦截

        String url = request.getRequestURI();
        Map parameterMap = request.getParameterMap();
        log.info("request start. url:{}", url);
        long start = System.currentTimeMillis();
        request.setAttribute(START_TIME, start);
        return true;
    }
    //postHandle在业务处理器处理请求执行完成后,生成视图之前执行。后处理(调用了Service并返回ModelAndView,但未进行页面渲染),有机会修改ModelAndView;
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        String url = request.getRequestURI().toString();
        long start = (Long) request.getAttribute(START_TIME);
        long end = System.currentTimeMillis();
        log.info("request finished. url:{}, cost:{}", url, end - start);
    }
    //afterCompletion在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面),可以根据ex是否为null判断是否发生了异常,进行日志记录;
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        String url = request.getRequestURI();
        long start = (Long) request.getAttribute(START_TIME);
        long end = System.currentTimeMillis();
        log.info("request completed. url:{}, cost:{}", url, end - start);

    }

}

新建一个RestInterceptorConfig配置类进行注册

@Configuration
public class RestInterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new RestInterceptor()).addPathPatterns("/*");
    }
}

RestInterceptorConfig配置类有下面4种配置方式:

  • implements WebMvcConfigurer : 不会覆盖@EnableAutoConfiguration关于WebMvcAutoConfiguration的配置
  • @EnableWebMvc + implements WebMvcConfigurer : 会覆盖@EnableAutoConfiguration关于WebMvcAutoConfiguration的配置
  • extends WebMvcConfigurationSupport :会覆盖@EnableAutoConfiguration关于WebMvcAutoConfiguration的配置
  • extends DelegatingWebMvcConfiguration :会覆盖@EnableAutoConfiguration关于WebMvcAutoConfiguration的配置
spring2.0 WebMvcConfigurationadpter 已经弃用了

关于@EnableWebMvc,WebMvcConfigurationSupport,WebMvcConfigurer和WebMvcConfigurationAdapter区别访问:Link 关于继承WebMvcConfigurationSupport静态资源不可以访问:Link

过滤器

Filter是Servlet技术中最实用的技术,Web开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。它主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理。使用Filter的完整流程:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。

方法一

新建一个RestFilter

@WebFilter(urlPatterns = "/*", filterName = "RestFilter")
@Slf4j
public class RestFilter  implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("RestFilter --- init");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.info("RestFilter --- doFilter");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {
        log.info("RestFilter --- destroy");
    }
}

在SpringbootApplication上面添加@ServletComponentScan注解

@ServletComponentScan
@SpringBootApplication
public class SpringbootApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootApplication.class, args);
    }

}

方法二(推荐)

同RestFilter.class一样但是不要加@WebFilter,也不需要在SpringbootApplication类加@ServletComponentScan通过配置类实现

@Slf4j
public class RestFilter  implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("RestFilter --- init");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.info("RestFilter --- doFilter");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {
        log.info("RestFilter --- destroy");
    }
}

配置类

@Configuration
public class RestFilterConfig {

    @Bean
    public FilterRegistrationBean filterRegistrationBean(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new RestFilter());
        filterRegistrationBean.setName("RestFilter");
        filterRegistrationBean.setOrder(1);
        filterRegistrationBean.addUrlPatterns("/*");
        return filterRegistrationBean;
    }
}

@WebFilter注解说明:

上源码

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebFilter {
  String description() default "";
  /**Filter显示名*/
  String displayName() default "";
  /**配置参数*/
  WebInitParam[] initParams() default {};
  /**Filter名称*/
  String filterName() default "";
 
  String smallIcon() default "";
 
  String largeIcon() default "";
  /**指定对哪些Servlet进行过滤*/
  String[] servletNames() default {};
  /**指定拦截的路径*/
  String[] value() default {};
  /**指定拦截的路径*/
  String[] urlPatterns() default {};
  /**指定Filter对哪种方式的请求进行过滤*/
  DispatcherType[] dispatcherTypes() default {DispatcherType.REQUEST};
  /**指定Filter是否支持异步模式*/
  boolean asyncSupported() default false;
}

监听器

listener是servlet规范中定义的一种特殊类。用于监听servletContext、HttpSession和servletRequest等域对象的创建和销毁事件。监听域对象的属性发生修改的事件。用于在事件发生前、发生后做一些必要的处理。其主要可用于以下方面:1、统计在线人数和在线用户2、系统启动时加载初始化信息3、统计网站访问量4、记录用户访问路径。 监听器就是监听某个对象的的状态变化的组件

监听器的相关概念:

事件源:被监听的对象  ----- 三个域对象 request  session  servletContext

监听器:监听事件源对象  事件源对象的状态的变化都会触发监听器 ---- yao 注册监听器:将监听器与事件源进行绑定

响应行为:监听器监听到事件源的状态变化时 所涉及的功能代码 ---- 程序员编写代码 950eda9f09e7039a8b30663883cdac7 方法一: 监控 Request 新建RequestListener继承ServletRequestListener

@WebListener
@Slf4j
public class RequestListener implements ServletRequestListener {


    @Override
    public void requestInitialized(ServletRequestEvent sce) {
        HttpServletRequest request = (HttpServletRequest) sce.getServletRequest();
        log.info("RequestListener----init---->"+request.getRequestURI());
    }
    @Override
    public void requestDestroyed(ServletRequestEvent sce) {
        HttpServletRequest request = (HttpServletRequest) sce.getServletRequest();
       log.info("RequestListener---desroyed----> "+request.getRequestURI());
    }
}

使用@WebListener注解实现,使用@WebListener与@WebFilter要在主类上面添加@ServletComponentScan注解 通过访问:http://localhost:8080/可以看到

···
RequestListener----init---->/
···
RequestListener---desroyed----> /

session监控 新建SessionListener 继承 HttpSessionListener

@WebListener
@Slf4j
public class SessionListener implements HttpSessionListener {
    @Override
    public void sessionCreated(javax.servlet.http.HttpSessionEvent se) {

        log.info("SessionListener----init---->"+se.getSession().getAttribute("user"));
    }


    @Override
    public void sessionDestroyed(javax.servlet.http.HttpSessionEvent se) {

        log.info("SessionListener---desroyed----> "+se.getSession().getAttribute("user"));
    }
}

在RestController新建两个请求控制Session的新建和销毁查看日志

    @GetMapping("/CreateSession")
    public String CreateSession(HttpSession Session) {
        Session.setAttribute("user", "jackgeeks");
        return "CreateSession";
    }

    @GetMapping("/DestroySession")
    public String DestroySession(HttpSession Session) {
        Session.invalidate();
        return "DestroySession";
    }

方法二 Context监控 新建ContextListener继承ServletContextListener

@Slf4j
public class ContextListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        ServletContext servletContext = sce.getServletContext();

        log.info("ContextListener--init .. ");
    }
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
       log.info("ContextListener---desroyed .. ");
    }
}

通过配置类

@Configuration
public class ContextListenerConfig {

    @Bean
    public ServletListenerRegistrationBean ListenerTow(){
        ServletListenerRegistrationBean<ContextListener>servletListenerRegistrationBean = new ServletListenerRegistrationBean<>(new ContextListener());
        return servletListenerRegistrationBean;
    }
}

服务器启动后会打印日志

ContextListener--init .. 

自定义监听器

新建ApplicationListener通过@EventListener定义监控器

@Slf4j
@Component
public class MyApplicationListener {
        @EventListener
        public void onApplicationEvent(String event) {
                log.info("MyApplicationListener接收到事件"+event);
                }
}

在RestController新建一个/Event git请求发发布事件

@GetMapping("/Event")
    public String Event() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyApplicationListener.class);
        System.out.println("发布事件");
        context.publishEvent("event");
        context.close();
        return "发布事件";
    }