什么是DI?
DI(Dependency Injection)依赖注入,指容器复制创建和维护对象之间的依赖关系,而不是通过对象本身复制自己的创建和解决自己的依赖。控制反转是通过依赖注入实现的。
依赖注入这个词从让人望而生畏,已经演变成一项复杂的编程技巧或设计模式理念。但依赖注入并不像它听上去那么复杂。在项目中应用DI,代码会变得异常简单并且更容易理解和测试(简单,易理解,易测试)。
任何一个有实际意义的应用都会由两个或者更多的类组成,这些类之间相互之间进行协作来完成特定的的业务逻辑。按照传统做法,每个对象负责管理与自己相互协作的的对象(即它所依赖的对象)的引用,这将会导致高度耦合和难以测试。耦合具有两面性:一方面紧密耦合的代码难以测试,难以复用、难以理解,并且典型地表现“打地鼠”式的bug特性。另一方面一定程度的耦合又是必须的。
通过DI,对象的依赖关系将由系统中负责协调各对象的第三方组件在创建对象的时候进行设定。对象无需自行的创建或管理它们的依赖关系。DI带来的最大的收益是——松耦合。其次是面向接口依赖的可替换(最常用的是测试的时候使用mock实现),那么在Spring中怎么实现的?创建应用组件之间的协作方式通常称为装配(wiring)。
怎么实现DI?
1.通过构造器实现注入
前提:被注入的类中必须提供所需的构造方法。
(如果对象是Java内部的简单类型等,可以直接设置value)
<bean id="hUser" class="com.openlab.homework1.User">
<constructor-arg index="0" value="张嘎"></constructor-arg>
<constructor-arg index="1" value="三天不打鬼子,手都痒痒" ></constructor-arg>
</bean>
(对象类型可以依赖ref注入)
<bean id="userService" class="com.oupeng.service.impl.UserServiceImpl">
<constructor-arg index="0"> <ref bean="userdao"/> </constructor-arg>
<constructor-arg
index="1" type="String"> <value>我是一个小小的小鸟...</value> </constructor-arg> </bean>
使用构造器注入时,注意最好在标签内声明Index指定注入的是哪个参数。
2.通过Setter实现注入
我们现在有一个TestEntity类,里面的属性如下所有set方法已经提供,注意通过setter注入必须提供对应的set方法。
public class TestEntity {
private String char1;
private String char2;
private User innerBean;
private List<String> list;
private String[] arr;
private Set<String> set;
private Map<String,String> map;
private Properties properties;
private String emptyString;
private String nullString;
<bean id="testEntity" class="com.openlab.pojo.TestEntity">
<property name="char1" value="H&H" ></property>
//&符号具有特殊含义通过&进行转义
<property name="char2">
<value><![CDATA[h&h]]></value>
//也可以通过<![CDATA[h&h]]>进行取值
</property>
<property name="innerBean" >
<bean class="com.openlab.pojo.User">
<property name="id" value="1001"></property>
<property name="username" value="执金吾"></property>
<property name="sign" value="剑来"></property>
</bean>
</property>
//对象类型可以通过配置bean或者已经装配了bean可以通过ref标签引用
<property name="list">
<list>
<value>赵云</value>
<value>关羽</value>
<value>张飞</value>
<value>黄总</value>
<value>马超</value>
</list>
</property>
<property name="arr">
<array>
<value>夏侯惇</value>
<value>典韦</value>
<value>夏侯渊</value>
<value>司马懿</value>
<value>曹彰</value>
</array>
</property>
<property name="set">
<set>
<value>孙策</value>
<value>孙权</value>
<value>周瑜</value>
<value>张昭</value>
<value>吕蒙</value>
</set>
</property>
<property name="map">
<map>
//map注意每一个键值对是一个entry,entry包含key和value
<entry>
<key>
<value>曹操</value>
</key>
<value>曹孟德</value>
</entry>
<entry>
<key>
<value>刘备</value>
</key>
<value>刘玄德</value>
</entry>
<entry>
<key>
<value>孙权</value>
</key>
<value>孙仲谋</value>
</entry>
</map>
</property>
<property name="properties">
<props>
<prop key="魏国">曹丕</prop>
<prop key="蜀国">刘备</prop>
<prop key="吴国">孙权</prop>
</props>
</property>
<property name="emptyString">
<value></value>
</property>
<property name="nullString">
<null></null>
</property>
</bean>
基于setter的p命名空间注入
p命名空间额注入方式是基于setter的,有以下两种格式。
- 简单类型:p:属性名=属性值
- bean类型:p:属性名-ref = 属性值
<bean id="dog" class="com.openlab.pojo.Dog" p:name="二哈" p:sex="雌性" p:varieties="哈士奇" p:age="1">
<!--<property name="name" value="二哈" />-->
<!--<property name="sex" value="雌性"/>-->
<!--<property name="varieties" value="哈士奇"/>-->
</bean>
<bean id="userService" class="com.openlab.service.impl.UserServiceImpl"
p:userDao-ref="userDao">
3.基于接口的DI注入
该点后续更新~