为什么在此 spring 应用程序的过滤器中自动装配的 bean 为空?
why is autowired bean null in filter in this spring application?
我已经简化了我们的生产应用程序以重现错误。
这是一个用于计算传入请求计数的演示应用程序。
当我调试项目时,我可以看到 Null Pointer Exception
被抛出
manager.incrementRequestCounter(url)
行 CounterMetricsFilter
class 如下所示。那是因为我的经理 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)
我认为您需要删除默认构造函数,只保留具有 @Autowired
依赖性的构造函数。否则 @Component
可能是使用默认构造函数创建的,并且依赖项不是 @Autowired
.
即只需删除这段代码:
public CounterMetricsFilter(){
}
过滤器由 servlet 容器实例化,因此 @Autowired
没有用。
您可以使用 DelegatingFilterProxy
让 Spring 实例化过滤器:
<filter>
<filter-name>counterMetricsFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
我已经简化了我们的生产应用程序以重现错误。
这是一个用于计算传入请求计数的演示应用程序。
当我调试项目时,我可以看到 Null Pointer Exception
被抛出
manager.incrementRequestCounter(url)
行 CounterMetricsFilter
class 如下所示。那是因为我的经理 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)
我认为您需要删除默认构造函数,只保留具有 @Autowired
依赖性的构造函数。否则 @Component
可能是使用默认构造函数创建的,并且依赖项不是 @Autowired
.
即只需删除这段代码:
public CounterMetricsFilter(){
}
过滤器由 servlet 容器实例化,因此 @Autowired
没有用。
您可以使用 DelegatingFilterProxy
让 Spring 实例化过滤器:
<filter>
<filter-name>counterMetricsFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>