- 问题描述
- 在使用 Map 工厂 管理没有接口实现的类时,通常以 Class 类型作为 key,如 OriginalClass.class。
- 如果目标类被 CGLIB 代理,实际存储在 Map 中的对象是 CGLIB 生成的代理对象,其 Class 名称与原始类不同,导致通过 OriginalClass.class 无法准确匹配到代理对象。
- 问题原因
- CGLIB 动态生成的代理类是目标类的子类,类名通常类似于 OriginalClass.EnhancerByCGLIB随机字符串。
- 使用 OriginalClass.class 作为 Map 的 key 时,无法匹配 CGLIB 的代理类。
- 解决方案
方案 1:使用 AopProxyUtils 提取原始目标类
在 Spring 环境下,可以使用 AopProxyUtils 提取代理对象的原始目标类并进行匹配:
javaCopy codeimport org.springframework.aop.framework.AopProxyUtils; Class<?> originalClass = AopProxyUtils.ultimateTargetClass(proxyInstance);
将提取的 originalClass 作为 Map 的 key,即可保证获取的对象与存储的代理对象一致。
方案 2:动态注册代理类的 Class
在存储代理对象到 Map 时,动态获取代理对象的真实 Class 并作为 key:
javaCopy codemap.put(proxyInstance.getClass(), proxyInstance);
在查找时,通过判断是否为代理类并获取其真实 Class:
javaCopy codeClass<?> key = proxyInstance instanceof Proxy ? AopProxyUtils.ultimateTargetClass(proxyInstance) : proxyInstance.getClass(); map.get(key);
方案 3:统一管理对象实例
在 Map 工厂中直接存储原始目标类和其代理对象的对应关系:
javaCopy codemap.put(OriginalClass.class, proxyInstance);
通过 getBean() 或类似方法,统一获取代理实例:
javaCopy codeObject bean = map.get(OriginalClass.class);
-
注意事项
-
避免直接使用
.class 获取实例:如果目标类被代理,直接通过 OriginalClass.class 获取实例会绕过代理逻辑。
- 校验代理类
:使用 AopUtils.isAopProxy() 或 instanceof 判断当前对象是否为代理对象:
javaCopy codeif (AopUtils.isAopProxy(proxyInstance)) { System.out.println("This is a proxy object"); }
- 代理与原始类匹配一致
:确保在 Map 中存储和查找时,统一使用原始类或代理类的 Class。
结论
对于没有接口实现的类,使用 Map 工厂管理时,如果以 Class 作为 key:
- CGLIB 代理会导致原始类的 .class 无法匹配代理对象。
- 使用 AopProxyUtils 提取目标类 是推荐的解决方案。
- 确保存储和查找的 key 是一致的(原始类或代理类)。