Spring拦截器中handler instanceof HandlerMethod始终返回false问题排查
在Spring Boot 2.7.3开发Web应用时,自定义拦截器的preHandle方法中出现异常情况:日志显示handler对象的类是org.springframework.web.method.HandlerMethod,且与代码中引用的HandlerMethod类使用同一个类加载器,但handler instanceof HandlerMethod的检查始终返回false。
相关代码片段
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { log.info("The specific class name of handler: {}", handler.getClass().getName()); log.info("Is handler a HandlerMethod class?: {}", (handler instanceof HandlerMethod)); log.info("The class loader of handler: {}", handler.getClass().getClassLoader()); log.info("The class loader of HandlerMethod: {}", HandlerMethod.class.getClassLoader()); if (!(handler instanceof HandlerMethod)) { log.info("Request intercepted, request URI: {}", request.getRequestURI()); return true; } // 其他业务逻辑... return true; }
日志输出
The specific class name of handler: org.springframework.web.method.HandlerMethod Is handler a HandlerMethod class?: false The class loader of handler: jdk.internal.loader.ClassLoaders$AppClassLoader@251a69d7 The class loader of HandlerMethod: jdk.internal.loader.ClassLoaders$AppClassLoader@251a69d7
已确认:
- 项目无类加载器相关特殊配置
- 未引入多版本Spring Framework
可能的原因及解决办法
1. 导入了错误的HandlerMethod类
检查代码中的import语句,确认引用的是**org.springframework.web.method.HandlerMethod**,而非其他包下的同名类(比如某些第三方库或自定义类中可能存在同名的HandlerMethod)。
2. 类路径中存在重复的Spring类文件
即使没有显式引入多版本Spring,也可能存在构建缓存、依赖传递导致的重复spring-web包。执行以下操作清理:
- Maven:运行
mvn clean install清理构建缓存并重做构建 - Gradle:运行
clean build清理缓存后重新构建 - 检查
target/classes或build/classes目录,确认没有重复的HandlerMethod.class文件
3. 字节码增强工具动态修改了类
如果项目中使用了Lombok、自定义字节码增强插件或监控工具(如SkyWalking、Pinpoint),可能会动态生成HandlerMethod的代理类,导致类对象与原HandlerMethod类不匹配。可以添加日志打印类对象的哈希值验证:
log.info("HandlerMethod class hash: {}", HandlerMethod.class.hashCode()); log.info("handler class hash: {}", handler.getClass().hashCode());
如果哈希值不同,说明是两个不同的Class对象。此时可以尝试暂时禁用字节码增强工具,验证问题是否消失。
4. 线程上下文类加载器与当前类加载器不一致
虽然日志显示类加载器相同,但可以尝试在preHandle方法中强制使用当前类加载器加载HandlerMethod类,再进行类型检查:
Class<?> handlerMethodClass = Class.forName("org.springframework.web.method.HandlerMethod", true, this.getClass().getClassLoader()); log.info("Is handler instance of loaded class?: {}", handlerMethodClass.isInstance(handler));
如果这个检查返回true,说明线程上下文类加载器导致了类加载的差异,可尝试手动指定类加载器进行类型判断。
内容的提问来源于stack exchange,提问作者YUXUAN ZOU

