java.lang.ClassCastException:类com.sun.proxy.$Proxy0无法转换为类com.example.MyInterface(com.sun.proxy.$Proxy0在加载器'app'的模块java.base中;com.example.MyInterface在加载器'app'的未命名模块中)
java.lang.ClassCastException: class com.sun.proxy.$Proxy0 cannot be cast to class com.example.MyInterface (com.sun.proxy.$Proxy0 is in module java.base of loader 'app'; com.example.MyInterface is in unnamed module of loader 'app')
ID: java/classcastexception-proxy-invocationhandler
版本兼容性
| 版本 | 状态 | 引入 | 弃用 | 备注 |
|---|---|---|---|---|
| Java 8 | active | — | — | — |
| Java 11 | active | — | — | — |
| Java 17 | active | — | — | — |
| Spring Framework 5.3.x | active | — | — | — |
| Spring Framework 6.x | active | — | — | — |
根因分析
当为代理的类加载器不可见的接口创建JDK动态代理(Proxy.newProxyInstance)时发生,通常因为接口由不同的类加载器加载或代理类来自不同模块。
English
This error occurs when a JDK dynamic proxy (Proxy.newProxyInstance) is created for an interface that is not visible to the proxy's class loader, typically because the interface is loaded by a different class loader or the proxy class is from a different module.
官方文档
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/reflect/Proxy.html解决方案
-
Ensure the interface is loaded by the same class loader as the proxy: `ClassLoader commonLoader = Thread.currentThread().getContextClassLoader(); MyInterface proxy = (MyInterface) Proxy.newProxyInstance(commonLoader, new Class[]{MyInterface.class}, handler);` -
For Spring applications, configure proxy-target-class="true" to use CGLIB proxies instead of JDK dynamic proxies: `<aop:aspectj-autoproxy proxy-target-class="true"/>` or `@EnableAspectJAutoProxy(proxyTargetClass = true)`.
-
Move the interface definition to a shared library jar that is loaded by the common class loader (e.g., the bootstrap or extension class loader) to avoid class loader isolation.
无效尝试
常见但无效的做法:
-
Casting the proxy to the concrete class instead of the interface
95% 失败
JDK dynamic proxies only implement interfaces, not concrete classes; casting to a concrete class will always fail.
-
Adding the interface to the classpath multiple times in different jars
70% 失败
Multiple class loaders loading the same interface cause type identity issues; the proxy implements one version, but the cast expects another.
-
Using CGLIB proxies instead without changing the interface visibility
60% 失败
CGLIB creates subclass proxies, which also require the target class to be accessible; the root cause (class loader mismatch) remains.