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

1、问题

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

模拟的代码如下:

自定义的Filter:

scala 复制代码
@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注解的类

less 复制代码
@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一起使用出现的问题,最终谜底仍未解开,只能给朋友们提个醒了。

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

原文链接: www.mangod.top/articles/20...mp.weixin.qq.com/s/vZCjamIzD...

相关推荐
optimistic_chen23 分钟前
【Java EE进阶 --- SpringBoot】Mybatis - plus 操作数据库
数据库·spring boot·笔记·java-ee·mybatis·mybatis-plus
来旺1 小时前
互联网大厂Java面试全解析及三轮问答专项
java·数据库·spring boot·安全·缓存·微服务·面试
摇滚侠1 小时前
Spring Boot 3零基础教程,yml文件中配置和类的属性绑定,笔记15
spring boot·redis·笔记
thginWalker1 小时前
使用Spring Boot构建消息通信层
spring boot
lang201509281 小时前
Spring Boot 外部化配置最佳实践指南
java·spring boot
摇滚侠2 小时前
Spring Boot 3零基础教程,WEB 开发 HTTP 缓存机制 笔记29
spring boot·笔记·缓存
Knight_AL2 小时前
Spring Boot 中使用自定义注解和 AOP 实现微服务日志记录(包含 URL、状态码和耗时信息)
linux·spring boot·微服务
Q_Q19632884752 小时前
python+vue的在线租房 房屋租赁系统
开发语言·vue.js·spring boot·python·django·flask·node.js
摇滚侠2 小时前
Spring Boot 3零基础教程,WEB 开发 内容协商 接口返回 YAML 格式的数据 笔记35
spring boot·笔记·后端
java水泥工3 小时前
旅游管理系统|基于SpringBoot和Vue的旅游管理系统(源码+数据库+文档)
spring boot·vue·计算机毕业设计·java毕业设计·旅游管理系统