研究了两天: 经过上文中的排除法: 造成问题的原因是要获取的 bean 中 有被切入的方法..
就是可能该类会使用反射生成一个类..
怎么测试呢?
想到 @Autowired 和 @Resource 这两个注解..
他们会通过 类型 和 名称去找容器中对应 的 bean ..
于是在 controller 中使用 这个注解 注入 zaService;
报错了 :
- Caused by: org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'zaSerivce' is expected to be of type 'com.mytest.context.impl.ZaSerivce' but was actually of type 'com.sun.proxy.$Proxy15'
- at org.springframework.beans.factory.support.DefaultListableBeanFactory.checkBeanNotOfRequiredType(DefaultListableBeanFactory.java:1510)
- at org.springframework.beans.factory.support.DefaultListableBeanFactory.checkBeanNotOfRequiredType(DefaultListableBeanFactory.java:1517)
- at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1489)
- at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104)
- at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)
- at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585)
- ... 67 more
这就说明了两个问题: 1. 为什么 byTpe 无法获取 bean ,, 因为它的类型根本就不是 com.mytest.context.impl.ZaSerivce 而是 com.sun.proxy.$Proxy15
2. byName 虽然可以获取但是会发现它的类型也已经不是 ZaService 了..
- ApplicationContext context = ApplicationContextUtils.context;
- ZaService z = (ZaService) context.getBean("zaService");
- java.lang.ClassCastException: com.sun.proxy.$Proxy15 cannot be cast to com.mytest.context.impl.ZaService
解决办法: 1. 通过 byType 获取 bean 时参数传 接口类的 class .. 不足: 只能有一个实现类.
2. byName 可以正常传参数 bean 的首字母小写.. 但是只能转换为接口类
IZaService z = (IZaService) context.getBean("zaService");
而我的业务参数是 实现类的全路径名, 所以特别适合 class.forName(); 然后 byType .. 可惜用不了.. 只能退而求其次了把参数 调整为 接口的全路径名.. 但是只能有一个实现类..
至于为什么被 切 的 类 在 spring 容器中的 type 变了, 那可能要考虑代理反射, 个人观点是 spring 默认使用 jdk 动态代理, 这种方式会生成一个全新的类, 比如本例的
$Proxy15, 然后通过这个代理类方法前后编入代码, 然后调用原始类的方法.. 说远了,....
注意 : spring 还有一种代理方式: CGLIB 是不会生成新的类, 那如果不生成新的类, 就不会出现上述的问题了,, 现在验证下 (spring 对没有实现接口的类的代理方式是 CGLib )
我们只要把 IZaServiec 去掉就行了不要 Zaserivce 实现它, 试试,, 日,, 真的正常了..
- @Service
- public class ZaService {
- @TestAnn
- /*@Override*/
- public void aa() {
- }
- }
- @ResponseBody
- @RequestMapping("/context")
- public String context(){
- ApplicationContext context = ApplicationContextUtils.context;
- ZaService z = (ZaService) context.getBean(ZaService.class);
- System.out.println(z);
- z.aa();
- return "context";
- }
- com.mytest.context.impl.ZaService@7cb0dfee
- <>>>>>>>>>>>>>>>>>>>>>>>after<><><><><>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
来源: http://www.bubuko.com/infodetail-2691939.html