@RefreshScope和过滤器Filter不要这样用

简介: 在注册自定义的OncePerRequestFilter所在的类上加了@RefreshScope导致自定义的OncePerRequestFilter不会被注册到上下文。

1、问题

最近在一个Spring应用中碰到这样的问题:Spring过滤器OncePerRequestFilterdoFilterInternal方法一直不被执行。最终发现是因为:在注册自定义的OncePerRequestFilter所在的类上加了@RefreshScope导致自定义的OncePerRequestFilter不会被注册到上下文。

模拟的代码如下:

自定义的Filter:

@Slf4j
public class CustomFilter extends OncePerRequestFilter {
    public CustomFilter() {
        log.warn("=================init CustomFilter====================");
    }
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        response.setStatus(200);
        response.setHeader("Content-Type", "application/json");
        response.getWriter().write("{\"age\":12}");
        response.getWriter().flush();
        response.flushBuffer();
//        filterChain.doFilter(request, response);
    }
}

使用@RefreshScope注解的类

@Configuration
@Slf4j
@RefreshScope
public class WebConfiguration implements WebMvcConfigurer {
    @Bean
    public CustomFilter customFilter() {
        return new CustomFilter();
    }
}

2、寻找原因

对于这个问题,在Google上也没搜索到合适的解答,自己在源码里打了断点,发现这个CustomFilter没有被执行init方法,所以最终也不会打印Filter xxx configured for use的日志,也就是说不会被注册进上下文。

我们知道filter过滤器是用于过滤请求的URL,遵循Servlet规范的,需要实现javax.servlet.Filter接口,依赖于Tomcat等容器。

Filter有3个的生命周期:服务启动时-init(FilterConfig arg0)、服务停止时-destroy()、拦截请求时-doFilter(ServletRequest srequest, ServletResponse sresponse, FilterChain filterChain)

只有过滤器执行了init方法,才能被注册进上下文。那上面自定义的过滤器CustomFilter为什么没有被执行init方法呢。

继续查阅了@ScopeRefesh相关原理,我们知道RefreshScope之所有能做热加载,主要做了以下动作:

  1. 单独管理Bean生命周期
    创建Bean的时候如果是RefreshScope就缓存在一个专门管理的ScopeMap中,这样就可以管理Scope是Refresh的Bean的生命周期了。
  2. 重新创建Bean
    外部化配置刷新之后,会触发一个动作,这个动作将上面的ScopeMap中的Bean清空,这样,这些Bean就会重新被IOC容器创建一次,使用最新的外部化配置的值注入类中,达到热加载新值的效果。

@ScopeRefesh也有失效的场景,RefreshBean被正确加载为CGLib动态代理对象就能正常动态刷新,有些不正常加载的场景,则会失效。比如组装加载WebFilter的时候会有两个重复Filter,一个是变化的,一个是不变化的。在Web应用里实际取到的是不变化的,所以修改配置会失效。

3、未果,惨淡收场

结合现状和原理来看,我还是未能破解这个谜题。上文中的问题是加载出了2个Filter,导致失效,而我这里出现的问题是自定义的Filter没有被加载。

我的猜测是,这个自定义Filter可能也是被创建了2个Bean,Bean-A是走了init方法,但实际应用中取到的Bean-B,由于某些原因,Bean-B再次创建的时候,没有走init方法,所以导致没有被注册到上下文。

或者是只创建一个Bean,但是由于使用@RefreshScope创建的Filter Bean缺少什么机制,导致没有被当作一种Filter去执行初始化。

折腾了几个小时,最终也没分析出个原因。这里只能给朋友们提个醒,@RefreshScope和过滤器Filter不要这样一起使用,否则会导致OncePerRequestFilterdoFilterInternal方法一直不被执行。

如果有知道谜底的朋友也请帮我解答下,谢谢!!!

文中查阅的RefreshScope的原理,参考了这篇CSDN博主Static_lin的文章《从RefreshScope实现原理看刷新配置失效问题》,文章用源码将原理分析的比较透彻。

总结:本文简单分析@RefreshScope和过滤器Filter一起使用出现的问题,最终谜底仍未解开,只能给朋友们提个醒了。

本篇完结!感谢你的阅读,欢迎点赞 关注 收藏 私信!!!

原文链接:http://www.mangod.top/articles/2023/09/02/1693623653306.htmlhttps://mp.weixin.qq.com/s/vZCjamIzDGgRef_m1YbXHA

相关文章
|
7月前
|
Java API 容器
Filter 过滤器实现
JavaWeb 组件 Servlet 提供了 Filter 过滤功能,其功能是对目标资源的请求和响应进行拦截,对拦截到的请求和响应做出特殊的功能处理,比如我们请求中有一些敏感信息过滤就是利用过滤器过滤。
|
2月前
|
前端开发 Java 中间件
过滤器(Filter)和拦截器(Interceptor)有什么不同?
文章比较了过滤器(Filter)和拦截器(Interceptor)的不同,包括它们的实现方式、应用场景、执行顺序、依赖框架和访问范围,指出过滤器通常用于全局和非业务相关的操作,而拦截器用于Spring MVC中与业务逻辑相关的处理。
212 8
|
应用服务中间件
15-Filter 过滤器2
15-Filter 过滤器2
83 0
|
Java
15-Filter 过滤器1
15-Filter 过滤器1
112 0
|
Java 应用服务中间件
Filter过滤器
Filter过滤器
Filter过滤器
|
API 数据安全/隐私保护 容器
Filter(过滤器)
Filter(过滤器)
|
API 容器
Filter过滤器的简单介绍与使用
Filter过滤器的简单介绍与使用
167 0
Filter过滤器的简单介绍与使用
|
应用服务中间件
filter 过滤器
Tomcat 每次创建 Filter 的时候,也会同时创建一个 FilterConfig 类,这里包含了 Filter 配置文件的配置信息。
filter 过滤器
|
Java 数据库连接 容器
拦截器Filter的使用
Filter 程序是一个实现了特殊接口的 Java 类,与 Servlet 类似,也是由 Servlet 容器进行调用和执行的。
146 0