Spring中配置了一个实现类,然后在 getBean 获取该 bean 时,将获取到的对象强制转换为实现类时出现以下错误:
Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy7 cannot be cast to com.spring.bean.ManImpl
接口类:
package com.spring.bean;
public interface HumanInter {
public void speak();
}
实现类:
package com.spring.bean;
import org.springframework.stereotype.Component;
@Component("man")
public class ManImpl implements HumanInter {
@Override
public void speak() {
System.out.println("I am a man...");
}
}
配置文件:
<?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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<context:component-scan base-package="com.spring.bean"></context:component-scan>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
运行类:
package com.spring.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.spring.bean.ManImpl;
public class Client {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ManImpl man = (ManImpl) ctx.getBean("man");
man.speak();
}
}
运行时出现上述错误。
修改办法:
① 把 ManImpl man = (ManImpl) ctx.getBean("man"); 的类型改为 HumanInter man = (HumanInter) ctx.getBean("man");
或者
② 看看自己是否配置了该实现类的切面类或者代理类,若有则把配置文件中的
<aop:aspectj-autoproxy></aop:aspectj-autoproxy> 去掉,即需要把该类的切面类或者代理类去掉(该方法会导致切
面类或代理类不起作用)
原因:(具体过程如果不理解可以去了解一下 JDK 动态代理的底层原理 https://www.imooc.com/learn/869)
这个错误一般都是代理类或切面类引起的,本程序中也一样,因为配置了一个切面类
因为当配置了一个切面类或者代理类时,IOC容器当创建这个实现类 bean 实例时,动态代理机制会根据该实现类的接口,
返回一个动态代理类,如上述的例子中执行 ctx.getBean("man") 时会先获取到的如下动态代理类,然后根据该动态代理的实例化
对象调用对应的方法:
public final class $Proxy0 extends Proxy implements HumanInter{}
因为该动态代理类 $Proxy0 实现了 HumanInter 接口,所以由该类的对象是 HumanInter 的一个实现类(但该实现类跟
ManImpl 实现类不等同,不可以进行强制转换,所以上述代码会出错)
验证 ctx.getBean("man") 生成的类是否是由动态代理类进行实例化的:
package com.spring.test;
import java.lang.reflect.Proxy;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.spring.bean.HumanInter;
import com.spring.bean.ManImpl;
import com.spring.bean.ManImpl2;
public class Client {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
HumanInter man = (HumanInter) ctx.getBean("man");
System.out.print("man instanceof ManImpl ---> ");
System.out.println(man instanceof ManImpl);
System.out.print("man instanceof Proxy ---> ");
System.out.println(man instanceof Proxy);
man.speak();
}
}
运行截图:
由运行截图可知,ctx.getBean("man") 获取到的类对象不是 ManImpl 类的对象,而是 Proxy 类的类对象。
去掉切面类后的运行截图: