You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在非Spring类或new实例化类中@Autowired?Filter注入Service遇NPE

解决Servlet Filter中注入Spring @Service的NPE问题

嘿,这个问题我太熟了!你遇到的NullPointerException根源很明确:你的CORSFilter是由Servlet容器(比如Tomcat)初始化和管理的对象,不属于Spring的Bean容器范畴,所以Spring根本没法帮你自动注入@Autowired标记的AccessLogService,自然调用的时候就会空指针啦。

下面给你几种实用的解决方案,按推荐程度排序:

方案一:把Filter交给Spring管理(最推荐)

这种方式最贴合Spring的设计思想,让Filter成为Spring Bean,再通过Spring提供的代理类让Servlet容器识别它。

步骤1:将Filter标记为Spring组件

给CORSFilter加上@Component注解,让Spring把它纳入Bean管理:

@Component
public class CORSFilter implements Filter { 
    @Autowired 
    private AccessLogService accessLogService; 

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { 
        AccessLogDTO rld = new AccessLogDTO(req); 
        accessLogService.addAccessLog(rld); 
        // 别忘了继续执行过滤器链
        chain.doFilter(req, res);
    }

    // init和destroy方法可以留空实现,除非你有初始化/清理逻辑
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {}

    @Override
    public void destroy() {}
}

步骤2:注册Filter到Servlet容器

如果是Spring Boot项目,直接用Java配置注册Filter即可:

@Configuration
public class FilterRegistrationConfig {
    @Bean
    public FilterRegistrationBean<CORSFilter> corsFilterRegistration(CORSFilter corsFilter) {
        FilterRegistrationBean<CORSFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(corsFilter);
        // 设置你需要拦截的URL路径,比如所有请求
        registrationBean.addUrlPatterns("/*");
        // 可以设置过滤器顺序,按需调整
        registrationBean.setOrder(1);
        return registrationBean;
    }
}

如果是传统的Spring MVC项目(用web.xml),则配置DelegatingFilterProxy来代理你的Spring Filter Bean:

<filter>
    <filter-name>cORSFilter</filter-name>
    <!-- 这个是Spring提供的代理类,负责把请求转交给Spring管理的Filter -->
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>cORSFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

注意:这里的filter-name必须和你的Filter Bean名称一致(默认是类名首字母小写,比如cORSFilter或者corsFilter,如果自定义了@Component的value就用自定义名称)。

方案二:在Filter的init方法中手动获取Spring Bean

如果你不想把Filter交给Spring管理,可以在Filter初始化时,手动从Spring的Web上下文里取出需要的Service:

public class CORSFilter implements Filter { 
    private AccessLogService accessLogService; 

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 从ServletContext中获取Spring的WebApplicationContext
        WebApplicationContext springContext = WebApplicationContextUtils.getWebApplicationContext(filterConfig.getServletContext());
        // 从上下文获取对应的Service Bean
        accessLogService = springContext.getBean(AccessLogService.class);
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { 
        AccessLogDTO rld = new AccessLogDTO(req); 
        accessLogService.addAccessLog(rld); 
        chain.doFilter(req, res);
    }

    @Override
    public void destroy() {}
}

这种方法的前提是Spring的WebApplicationContext已经被初始化(一般Spring MVC项目都会通过ContextLoaderListener加载上下文,所以没问题)。

方案三:使用@Configurable(不推荐,配置复杂)

这个方法需要启用AspectJ织入,让Spring即使对new出来的对象也能注入依赖,配置起来比较繁琐,除非你有特殊场景,否则不建议用。简单示例:

  1. 给Filter加上@Configurable注解:
@Configurable
public class CORSFilter implements Filter { 
    @Autowired 
    private AccessLogService accessLogService; 

    // 其他方法不变
}
  1. 然后在Spring配置中启用AspectJ自动代理,并配置织入相关的依赖和插件,这个过程比较麻烦,所以优先前两种方案。

内容的提问来源于stack exchange,提问作者Magno C

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:16:56