在测试Spring使用xml实现aop时出现以下错误:Exception in thread "main" org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'performance' must be of type [Concert.PerformanceImpl], but was actually of type [com.sun.proxy.$Proxy3]
具体代码如下:
Audience类:
package Concert; import org.aspectj.lang.annotation.*; //@Aspect public class Audience { //@Pointcut("execution(* Concert.Performance.perform(..))") public void perform(){} //@Before("perform()") public void performBefore(){ System.out.println("表演即将开始,请各位入座"); } //@AfterReturning("perform()") public void performce(){ System.out.println("请尽情开始你的表演。"); } //@After("perform()") public void performAfter(){ System.out.println("表演结束,请离场"); } @AfterThrowing("execution(* Concert.Performance.performFailed())") public void Over(){ System.out.println("表演失败,一切都完了"); } }
Performance接口:
package Concert; public interface Performance { public void perform(); public void performFailed() throws Exception; }
PerformanceImpl实现类:
package Concert; //@Component public class PerformanceImpl implements Performance { public void perform(){ System.out.println("蹦擦擦,蹦擦擦..."); } public void performFailed() throws Exception { throw new Exception(); } }
xml文件内容:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--<aop:aspectj-autoproxy proxy-target-class="true"/>--> <bean id="performance" class="Concert.PerformanceImpl"/> <bean id="audience" class="Concert.Audience" /> <aop:config> <aop:aspect ref="audience"> <aop:pointcut id="perform" expression="execution(* Concert.Performance.perform(..))"/> <aop:before method="performBefore" pointcut-ref="perform"/> <aop:before method="performBefore" pointcut-ref="perform"/> <aop:after method="performAfter" pointcut-ref="perform"/> <aop:after-returning method="performce" pointcut-ref="perform"/> <aop:after-throwing method="Over" pointcut="execution(* Concert.Performance.perform(..))"/> </aop:aspect> </aop:config> </beans>
测试内容:
import Concert.Audience; import Concert.PerformanceImpl; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { /*AnnotationConfigApplicationContext apx = new AnnotationConfigApplicationContext(); apx.register(Config.class); apx.refresh();*/ ClassPathXmlApplicationContext apx = new ClassPathXmlApplicationContext("classpath:Config/AspectsConfig.xml"); Audience audience = apx.getBean(Audience.class); audience.performAfter(); PerformanceImpl performance = apx.getBean("performance",PerformanceImpl.class); performance.perform(); try{ performance.performFailed(); }catch (Exception e){ // e.printStackTrace(); } apx.close(); } }
原因:Spring 有两种代理动态代理模式,一种是基于接口的JDK动态地理,一种是基于类的CGLibs动态代理,Spring默认是使用JDK动态代理的,所以要么使用JDK动态代理,要么使用CGLibs实现动态代理。
解决方法:
1、使用基于接口的JDK动态代理:将测试代码中的
PerformanceImpl performance = apx.getBean("performance",PerformanceImpl.class);
改为
Performance performance = apx.getBean("performance", Performance.class);
2、使用基于类的CGLIBS动态代理:在配置文件中添加
<aop:aspectj-autoproxy proxy-target-class="true"/>强制使用类代理模式。