最近升级了项目中使用的 Spring Boot 版本,从 1.3.5 升级到了 2.2.5。升级过程中遇到了一个问题,原有的 Interceptor 不工作了,现象是 这样的:
org.springframework.web.servlet.resource.ResourceHttpRequestHandler cannot be cast to org.springframework.web.method.HandlerMethod
相关的代码如下,它实现了对访问用户的记录:
public class ActionInterceptor implements HandlerInterceptor {
private Logger logger = LoggerFactory.getLogger(getClass());
private ThreadLocal<Long> startTime = new ThreadLocal<>();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object methodObj) throws Exception {
HandlerMethod method = (HandlerMethod) methodObj;
VisitorLog visitLog = method.getMethodAnnotation(VisitorLog.class);
if (visitLog != null) {
logVisitors(request, visitLog);
}
RoleProtecting roleProtecting = method.getMethodAnnotation(RoleProtecting.class);
}
抛出异常的在这一句:HandlerMethod method = (HandlerMethod) methodObj
,原因在于 methodObj
的类型为ResourceHttpRequestHandler
。 这是 Spring Boot 2(Spring 5.x) 的一个改变:对于静态资源的请求也会转发到 interceptor
。这就是这个异常的原因
Fix 的办法就很简单了,在强制转换前,判断一下 instance 的类型即可:
if (!(methodObj instanceof HandlerMethod)) {
return true;
}
HandlerMethod method = (HandlerMethod) methodObj;
另外一个方法,就是在添加 interceptor 时,指定 interceptor 要处理的请求的范围,比如使用:excludePathPatterns
把静态资源的 URL 排除,比如:
@Configuration
public class ControllerConfiguration implements WebMvcConfigurer {
private final AdminOnlyInterceptor adminInterceptor;
@Autowired
public ControllerConfiguration(AdminInterceptor adminInterceptor) {
this.adminInterceptor = adminInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(adminInterceptor)
.addPathPatterns("/rest-api-root/**"); // White list paths
//.excludePathPatterns("/static-resource-root/**"); // Black list paths
}
}
这个 Spring Boot 的变化还是需要引起注意,升级的过程中其实要处理的问题还是比较多的,我在第一次尝试升级的时候,直接就把这个 interceptor 直接注释掉了,后面静下来看,才发现根本原因