过滤器 监听器 拦截器

搞明白监听器、过滤器、拦截器的作用和使用方式,首先需要了解spring对于这三个的加载时机是在怎么样的,如下图:

 

 

 

 

spring对于这三者依次是先执行过滤器(多个过滤器采用责任链模式依次调用执行),紧接着是监听器,最后才是拦截器。

而这三者的作用:

过滤器(Filter):当你有一堆东西的时候,你只希望选择符合你要求的某一些东西。定义这些要求的工具,就是过滤器。(不更改对象的行为和属性)

监听器(Listener):当一个事件发生的时候,你希望获得这个事件发生的详细信息,而并不想干预这个事件本身的进程,这就要用到监听器。 (不更改对象的行为和属性)

拦截器(Interceptor):在一个流程正在进行的时候,你希望干预它的进展,甚至终止它进行,这是拦截器做的事情。(更改对象的行为和属性)

能力逐渐增强:过滤器-->监听器-->拦截器 

 

springboot中
过滤器
过滤器不需要额外的配置,直接交由spring管理即可,或者使用@WebFilter,二者选其一,使用@WebFilter,需要在启动类上开启对servlet注解的支持

在SpringBootApplication上使用@ServletComponentScan注解后,Servlet、Filter、Listener可以直接通过@WebServlet、@WebFilter、@WebListener注解自动注册,无需其他代码
 

@MapperScan("com.hzteh.mapper")
@SpringBootApplication
@ServletComponentScan
public class HztechApplication {

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

}

 

/**
 * @ClassName CrosFilter
 * @Description 跨域过滤器,springboot直接交由spring管理就可直接使用,spring需要在web.xml中配置此过滤器
 * @Date 2021/9/7 11:13
 */
@Component
//@WebFilter(urlPatterns = "/api/*", filterName = "loginFilter") //配置过滤请求等参数
public class CrosFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("启动时初始化???");
    }
 
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("新的请求每次都会执行请求时机????");
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        //允许跨域的域
        response.setHeader("Access-Control-Allow-Origin", "*");
        //允许携带脚本程序
        response.setHeader("Access-Control-Allow-Credentials","true");
        //允许的跨域请求
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE,PUT,PATCH");
        //允许脚本访问返回的头
        response.setHeader("Access-Control-Expose-Headers", "true");
        //缓存此请求秒数
        response.setHeader("Access-Control-Max-Age", "3600");
        //自定义的头部
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with, content-type");
        filterChain.doFilter(servletRequest, servletResponse);
    }
 
    @Override
    public void destroy() {
        System.out.println("服务器停止时销毁??");
    }
}

 

 

监听器

监听器在类上使用@WebListener标注,并且启动类上使用了@ServletComponentScan

@WebListener
public class MyRequestListener implements ServletRequestListener {
    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        System.out.println("销毁。。。");
    }
 
    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        System.out.println("初始化、、、");
    }
}

拦截器

拦截器的使用需要添加配置类,注册拦截器,不然不生效

@Component
public class UserInterceptor implements HandlerInterceptor {
 
    /**
     * 每次请求之前执行
     * @param request
     * @param response
     * @param handler
     * @return true表示继续流程(如调用下一个拦截器或处理器);
     *         false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("新的请求:"+handler);
        return true;
    }
 
    /**
     * 请求处理结束,(但在渲染视图之前)执行,此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
        System.out.println("请求处理后视图前:"+handler+"==="+modelAndView);
    }
 
    /**
     * 请求除磷结束,渲染视图结束后执行
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        System.out.println("请求完全执行完成:"+handler+"--"+ex);
    }
}

@Configuration

/**
 * @ClassName InterceptorConfig
 * @Description 拦截器的注册和配置 extends WebMvcConfigurerAdapter过时了
 *  1、继承WebMvcConfigurationSupport
 *  2、实现WebMvcConfigurer
 *  但是继承WebMvcConfigurationSupport会让Spring-boot对mvc的自动配置失效。根据项目情况选择。
 *  现在大多数项目是前后端分离,并没有对静态资源有自动配置的需求所以继承WebMvcConfigurationSupport也未尝不可。
 */
 
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    /**
     * 创建拦截器对象
     * @return
     */
    @Bean
    public HandlerInterceptor getMyInterceptor(){
        return new UserInterceptor();
    }
 
 
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        InterceptorRegistration interceptor = registry.addInterceptor(getMyInterceptor());
        // 拦截所有、排除
        interceptor.addPathPatterns("/**")
                .excludePathPatterns("/user/login");
    }
}

引自:

(87条消息) spring和springboot中对应监听器、过滤器、拦截器的使用区别_记录学习日常的博客-CSDN博客

过滤器和拦截器对比

 
实现原理不同:过滤器是基于函数回调;拦截器是基于java的反射机制的。

使用范围不同:过滤器依赖与servlet容器,拦截器不依赖与servlet容器(拦截器是Spring容器内的,是Spring框架支持的)。

因为Filter是Servlet规范中规定的,所有只能用于WEB中;而拦截器既可以用于WEB,也可以用于Application、Swing中。

触发时机不同:过滤器是在请求进入tomcat容器后,但请求进入servlet之前进行预处理的;请求结束返回也是,是在servlet处理完后,返回给前端之前。

拦截器可以深入到方法的前后、异常抛出前后等更深层次的程度作处理(这里也在一定程度上论证了拦截器是利用java的反射机制实现的),所以在Spring框架中,优先使用拦截器。

拦截的请求范围不同:过滤器则可以对几乎所有的请求起作用;拦截器只能对action请求起作用。

注入Bean情况不同:拦截器先于ApplicationContext加载,所以拦截器无法注入Spring容器管理的bean。

解决办法:拦截器不使用@Component加载,改为使用@Configuration+@Bean加载。

控制执行顺序不同:过滤器用@Order注解控制执行顺序,通过@Order控制过滤器的级别,值越小级别越高越先执行;拦截器默认的执行顺序,就是它的注册顺序,也可以通过Order手动设置控制,值越小越先执行。

注意:拦截器有前置处理和后置处理,前置处理越线,后置处理就越后。

二、过滤器
Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序,主要的用途是过滤字符编码、做一些业务逻辑判断等。

其工作原理是,只要你在web.xml文件配置好要拦截的客户端请求,它都会帮你拦截到请求,此时你就可以对请求或响应(Request、Response)统一设置编码,简化操作;同时还可以进行逻辑判断,如用户是否已经登录、有没有权限访问该页面等等工作,它是随你的web应用启动而启动的,只初始化一次,以后就可以拦截相关的请求,只有当你的web应用停止或重新部署的时候才能销毁。

Spring的web包中中提供有很多过滤器,这些过滤器位于org.springframework.web.filter。

过滤器放在web资源之前,可以在请求抵达它所应用的web资源(可以是一个Servlet、一个Jsp页面,甚至是一个HTML页面)之前截获进入的请求,并且在它返回到客户之前截获输出请求。

过滤器:用来拦截请求,处于客户端与被请求资源之间,目的是重用代码。
过滤链:在web.xml中哪个过滤器先配置,哪个就先调用。在filter中也可以配置一些初始化参数。
Java中的Filter 并不是一个标准的Servlet ,它不能处理用户请求,也不能对客户端生成响应。 主要用于对HttpServletRequest 进行预处理,也可以对HttpServletResponse 进行后处理,是个典型的处理链。

过滤器的分类
用户授权的Filter:Filter负责检查用户请求,根据请求过滤用户非法请求。

日志Filter:详细记录某些特殊的用户请求。

负责解码的Filter:包括对非标准编码的请求解码。

能改变XML 内容的XSLTFilter等。

过滤器的作用
在HttpServletRequest 到达Servlet 之前,拦截客户的HttpServletRequest 。据需要检查HttpServletRequest ,也可以修改HttpServletRequest 头和数据。

在HttpServletResponse 到达客户端之前,拦截HttpServletResponse 。根据需要检查HttpServletResponse ,可以修改HttpServletResponse 头和数据。

过滤器的实现方式
直接实现Filter,这一类过滤器只有CompositeFilter;

继承抽象类GenericFilterBean,该类实现了javax.servlet.Filter,这一类的过滤器只有一个,即DelegatingFilterProxy;

继承抽象类OncePerRequestFilter,该类为GenericFilterBean的直接子类,这一类过滤器包括CharacterEncodingFilter、HiddenHttpMethodFilter、HttpPutFormContentFilter、RequestContextFilter和ShallowEtagHeaderFilter;

继承抽象类AbstractRequestLoggingFilter,该类为OncePerRequestFilter的直接子类,这一类过滤器包括CommonsRequestLoggingFilter、Log4jNestedDiagnosticContextFilter和ServletContextRequestLoggingFilter。

三、拦截器
SpringMVC 中的Interceptor 拦截器的主要作用就是拦截用户的 url 请求,并在执行 handler 方法的前中后加入某些特殊请求,比如通过它来进行权限验证,或者是来判断用户是否登陆。

拦截器的实现方式
SpringMVC 中的Interceptor 拦截请求是通过HandlerInterceptor 来实现的。在SpringMVC 中定义一个Interceptor 非常简单,主要有两种方式:

定义的Interceptor类要实现了Spring 的HandlerInterceptor 接口,或者是这个类继承实现了HandlerInterceptor 接口的类,比如Spring 已经提供的实现了HandlerInterceptor 接口的抽象类HandlerInterceptorAdapter

实现Spring的WebRequestInterceptor接口,或者是继承实现了WebRequestInterceptor的类。

四、二者总结
过滤器:用于属性甄别,对象收集(不可改变过滤对象的属性和行为)

拦截器:用于对象拦截,行为干预(可以改变拦截对象的属性和行为)
————————————————
版权声明:本文为CSDN博主「骑个小蜗牛」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/JokerLJG/article/details/121538821

posted on 2023-02-26 21:54  hztech  阅读(96)  评论(0编辑  收藏  举报

导航