【问题标题】:why is autowired bean null in filter in this spring application? [duplicate]为什么在这个 Spring 应用程序中的过滤器中自动装配的 bean 为空? [复制]
【发布时间】:2015-12-10 23:34:52
【问题描述】:

我已经简化了我们的生产应用程序来重现错误。

这是一个计算传入请求计数的演示应用程序。

当我调试项目时,我可以看到Null Pointer Exception 被抛出 manager.incrementRequestCounter(url) 类中的 CounterMetricsFilter 行如下所示。那是因为我的经理 autowired 是 NULL。

但是,CounterController 中的同一经理 autowired 不为空。我通过调试器确认了这一点。

这里有什么问题? filters 可以不是beans 吗?如果在Spring MVC 应用程序中不使用web.xml,我怎样才能实现这一点。

谢谢

Controller

@Controller
@RequestMapping("/counter")
public class CounterController {

@Autowired
CounterManager manager;

 @RequestMapping(value = "/counterMetrics", method = RequestMethod.GET)
    @ResponseBody
    public Map getFeatureStatus(final HttpServletResponse response) {
        System.out.println("returning feautre status");
        return manager.getQueryCounts();
    }
}

Manager

@Service
public class CounterManager {

private Map<String,Integer> queryCounts =
            new ConcurrentHashMap<String,Integer>(1000);

int threshold;
long timestamp;

 @Autowired
  public CounterManager(@Value("${healthThreshold: 10}")
                                 int threshold) {
      this.threshold = threshold * MEGABYTES;
      this.timestamp = System.currentTimeMillis();
  }


 public void incrementRequestCounter(String urlPath){
     Integer oldVal, newVal;
     do {
       oldVal = queryCounts.get(model);
       newVal = (oldVal == null) ? 1 : (oldVal + 1);
     } while (!queryCounts.replace(model, oldVal, newVal));
 }

public Map<StatusUrlModel, Integer> getQueryCounts() {
    return queryCounts;
}

}

Filter

@Order(Ordered.HIGHEST_PRECEDENCE)
@Component
public class CounterMetricsFilter extends OncePerRequestFilter {

    @Autowired
    CounterManager manager;

    public CounterMetricsFilter(){

    }


    @Override
    protected void doFilterInternal(HttpServletRequest request,
            HttpServletResponse response, FilterChain chain) throws ServletException,
            IOException {
        String path = new UrlPathHelper().getPathWithinApplication(request);
        try {
            chain.doFilter(request, response);
        }
        finally {
            recordMetrics(request, path);
        }
    }

   private void recordMetrics(String path) {
        try {
        manager.incrementRequestCounter(url);
        }
        catch (Exception ex){
            System.out.println("exception is thrown " + ex.getCause());
            ex.printStackTrace();
        }
    }
}

更新

在控制台上打印以下内容:

exception is thrown null(来自上面的 CounterMetricsFilter)。 堆栈跟踪:

java.lang.NullPointerException
    at com.myapp.filter.CounterMetricsFilter.recordMetrics(CounterMetricsFilter.java:81)
    at com.myapp.filter.CounterMetricsFilter.doFilterInternal(CounterMetricsFilter.java:63)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at com.myapp.filter.RequestWrapperFilter.doFilter(RequestWrapperFilter.java:24)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at com.myapp.filter.GCCORSFilter.doFilter(GCCORSFilter.java:37)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

【问题讨论】:

    标签: spring spring-mvc servlet-filters autowired


    【解决方案1】:

    过滤器由 servlet 容器实例化,因此 @Autowired 无用。

    您可以使用DelegatingFilterProxy 让 Spring 实例化过滤器:

    <filter>
      <filter-name>counterMetricsFilter</filter-name>
      <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    

    【讨论】:

    • 正如我提到的,我们不使用web.xml。有没有其他方法可以使用@Configuration 进行配置?
    • @zeroflgagL:我认为你的说法在这种情况下是不正确的
    • @brainstorm 你可能有一些带有onStartup 方法的...Initializer 类。在那里你可以打电话给servletContext.addFilter("counterMetricsFilter", new DelegatingFilterProxy("counterMetricsFilter"));
    • @zeroflagL:我尝试了您在onStartup 方法中的建议。我得到org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'counterMetricsFilter' is defined
    • 试试@Component("counterMetricsFilter")CounterMetricsFilter 是否在应用程序启动时扫描的包中?
    【解决方案2】:

    我认为您需要删除默认构造函数并仅保留具有 @Autowired 依赖项的构造函数。否则@Component 可能是使用默认构造函数创建的,并且依赖项不是@Autowired

    即只需删除这段代码:

    public CounterMetricsFilter(){
    
    }
    

    【讨论】:

    • 我一开始就没有这个。我稍后把它放在看看它是否修复了错误。但它没有
    • 如果您只有具有自动装配依赖关系的构造函数,它将自动装配该字段或尝试失败。没有其他选择。异常看起来会有所不同。我仍然相信这是问题所在。如果您不同意,请显示您看到的堆栈跟踪。
    • 我已经更新了确切的代码。我使用了现场注入。请参阅上面的更新
    • 问题不是你想的那样。 @Autowire 是强制性的。如果 Spring 不能自动装配该字段,它根本不会启动。显示完整的堆栈跟踪。
    • 或者你正在创建自己调用构造函数而不是让 Spring 实例化它。
    猜你喜欢
    • 2015-11-14
    • 1970-01-01
    • 1970-01-01
    • 2018-04-16
    • 2013-09-28
    • 2011-09-28
    • 2014-09-08
    • 1970-01-01
    • 2016-01-09
    相关资源
    最近更新 更多