这是一个常见的Spring配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 将指定类TestDIDaoImpl配置给Spring,让Spring创建其实例 -->
<bean id="myTestDIDao" class="dao.TestDIDaoImpl" />
<!-- 使用构造方法注入 -->
<bean id="testDIService" class="service.TestDIServiceImpl">
<!-- 将myTestDIDao注入到TestDIServiceImpl类的属性 testDIDao上-->
<constructor-arg index="0" ref="myTestDIDao"/>
</bean>
</beans>
使用动态代理的时候,下面明明已经指定了要代理的对象,为什么上面还要多此一举指定这个对象所实现的接口呢?
原因是:Spring动态代理功能的实现是基于java的动态代理机制。
主要的原理是使用Proxy.newProxyInstance()方法创建一个代理对象来代理指定的类,查阅JDK文档这个方法有三个参数:
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
第一个参数为要代理的类,第二个参数为这个类的接口,第三个暂且不管。
原来java实现动态代理的时候要求必须有接口类,导致spring也这么向我们要求了。
我们再来看看 越過山丘 博主的解释:
原文链接:https://www.cnblogs.com/lee10010/p/7888121.html
首先说明,注入的对象确实为实现类的对象。(并不是实现类的代理对象,注入并不涉及代理)
如果只是单纯注入是可以用实现类接收注入对象的,但是往往开发中会对实现类做增强,如事务,日志等,实现增强的AOP技术是通过动态代理实现的,而Spring默认是JDK动态代理,对实现类对象做增强得到的增强类与实现类是兄弟关系,所以不能用实现类接收增强类对象,只能用接口接收。如:
//接口:IA
//实现类:AImpl
//增强类:AImplProxy
AImpl aImpl = new AImpl();
//通过JDKProxyFactory创建代理对象
JDKProxyFactory factory = new JDKProxyFactory(aImpl);
//这个增强类对象aImplProxy 只能强转为IA,而不能转为AImpl,
//因为JDK代理得到的AImplProxy类与AImpl是兄弟关系而非父子
AImplProxy aImplProxy = factory.createProxy();
由于以上原因,如果将对象注入给实现类而非接口的话,在代理时就会报错。解决方法,让Spring强制使用Cglib代理:
<aop:aspectj-autoproxy proxy-target-class="true"/>
cglib代理类和实现类之间是父子关系,自然可以用父类(实现类)去接收子类对象(代理类对象即增强类对象)。
不过应该不会需要这么做,使用接口本来就是解耦的,你直接用实现类接收注入对象岂不是失去了注入的意义。(为什么不直接new一个呢?)
参考文章:
https://blog.csdn.net/withiter/article/details/5474407
https://bbs.csdn.net/topics/390683139
https://blog.csdn.net/hzy38324/article/details/78013136
https://www.cnblogs.com/lee10010/p/7888121.html