Spring使用ProxyFactoryBean注入guitarist属性报类型转换错误如何解决?
问题根因
你遇到的类型转换错误是Spring AOP默认代理机制导致的:
Spring的ProxyFactoryBean默认优先使用JDK动态代理,JDK动态代理只能基于接口生成代理对象,生成的代理对象只会实现目标类的所有接口(本次场景中GrammyGuitarist仅实现了Singer接口,所以代理类也只实现了Singer接口),不会继承目标类本身,因此代理对象无法强转为GrammyGuitarist类型,注入时就会报转换失败错误。
代理是否可以转换为目标类型
不建议直接将代理转换为原始目标类型,这种操作会绕开代理的增强逻辑,失去AOP的作用。如果确实需要强制获取原始对象,可以通过Spring的Advised接口提取,但属于非常规操作,不推荐在业务代码中使用:
Object proxy = ctx.getBean("proxyOne"); Advised advised = (Advised) proxy; GrammyGuitarist target = (GrammyGuitarist) advised.getTargetSource().getTarget();
可行的修复方案
方案1:强制使用CGLIB代理(推荐,改动最小)
CGLIB代理是通过生成目标类的子类实现代理的,生成的代理类是目标类的子类,所以可以直接赋值给GrammyGuitarist类型的变量。Spring 5及以上版本已经内置了CGLIB依赖,不需要额外引入第三方包。
仅需修改XML配置中的两个ProxyFactoryBean定义,添加proxyTargetClass="true"属性即可:
<bean id="proxyOne" class="org.springframework.aop.framework.ProxyFactoryBean" p:target-ref="johnMayer" p:interceptorNames-ref="interceptorAdviceNames" p:proxyTargetClass="true"/> <bean id="proxyTwo" class="org.springframework.aop.framework.ProxyFactoryBean" p:target-ref="johnMayer" p:interceptorNames-ref="interceptorAdvisorNames" p:proxyTargetClass="true"> </bean>
方案2:基于接口编程(符合Spring开发规范)
如果不想使用CGLIB代理,调整代码遵守面向接口编程的规范即可:
- 把
GrammyGuitarist中用到的非接口方法补充到Singer接口定义中:
public interface Singer { void sing(); void sing(Guitar guitar); void talk(); }
- 修改
Documentarist类的guitarist属性类型为Singer接口:
public class Documentarist { protected Singer guitarist; public void execute() { guitarist.sing(); guitarist.talk(); } public void setGuitarist(Singer guitarist) { this.guitarist = guitarist; } }
两种方案修改后都可以正常运行,AOP增强逻辑也会正常生效。
内容的提问来源于stack exchange,提问作者dzen Dao
相关产品推荐
相关产品推荐

