When a filter class annotated with @RefreshScope extends OncePerRequestFilter, it fails to function correctly. The issue arises because the filter is instantiated as a proxy (using CGLIB), causing certain properties of the parent class, such as the logger in GenericFilterBean, to be null.

Reproduction Code:

@RefreshScope
public class MyFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        // Filter logic here
        filterChain.doFilter(request, response);
    }
}

Root Cause: The @RefreshScope annotation creates a CGLIB proxy for the filter bean. The GenericFilterBean class, which is part of the Spring Framework and serves as a base class for OncePerRequestFilter, contains a protected final Logger logger field. This field is initialized directly in the parent class and does not work properly when the bean is proxied. As a result, the logger instance is null, leading to NullPointerException when logging is attempted.

spring-framework version: 6.2.1 spring-boot: 3.4.0 spring-cloud-context: 3.1.7

ERROR

java.lang.NullPointerException: Cannot invoke "org.apache.commons.logging.Log.isDebugEnabled()" because "this.logger" is null
    at org.springframework.web.filter.GenericFilterBean.init(GenericFilterBean.java:239)
    at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:245)
    at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:102)
    at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:3857)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:4462)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1203)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1193)
    at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java)
    at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
    at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145)
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:749)
    at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:772)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1203)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1193)
    at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java)
    at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
    at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145)
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:749)
    at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:203)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164)
    at org.apache.catalina.core.StandardService.startInternal(StandardService.java:415)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164)
    at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:870)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164)
    at org.apache.catalina.startup.Tomcat.start(Tomcat.java:437)
    at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:128)
    at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.<init>(TomcatWebServer.java:107)
    at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getTomcatWebServer(TomcatServletWebServerFactory.java:516)

Suggested Solution:

to make logger defined in GenericFilterBean

    protected final Log logger = LogFactory.getLog(getClass());

static

    protected static final Log logger = LogFactory.getLog(getClass());

Comment From: snicoll

Please report that to the Spring Cloud project where they can assess whether adding @RefreshScope on a filter makes sense.