Spring-(3)Spring DI
DI:Dependency Injection,即「依赖注入」,依赖注入可以有高效的解耦合的能力。可以说,依赖注入仅仅是控制反转的一个具体的例子,当编写一个复杂的 Java 应用程序时,应用程序类应该尽可能的独立于其他的 Java 类来增加这些类可重用的可能性,当进行单元测试时,可以使它们独立于其他类进行测试。依赖注入有助于将这些类粘合在一起,并且在同一时间让它们保持独立。我们将这两个部分拆开来理解,依赖的关系就像是类里面套着另一个类,例如车店是一个类,车店类里面有一个属性是车主类,那么车店类就依赖了车主类,这就是依赖关系,那注入的意思是车主类通过IOC容器注入到车店!
每个基于应用程序的 java 都有几个对象,这些对象一起工作来呈现出终端用户所看到的工作的应用程序。当编写一个复杂的 Java 应用程序时,应用程序类应该尽可能独立于其他 Java 类来增加这些类重用的可能性,并且在做单元测试时,测试独立于其他类的独立性。依赖注入(DI)有助于把这些类粘合在一起,同时保持他们独立。
Spring 有两种依赖注入类型:
- Constructor-based dependency injection:当容器调用带有多个参数的构造函数类时,实现基于构造函数的 DI,每个代表在其他类中的一个依赖关系;
- Setter-based dependency injection:基于 setter 方法的 DI 是通过在调用无参数的构造函数或无参数的静态工厂方法实例化 bean 之后容器调用 beans 的 setter 方法来实现的。
你可以混合这两种方法,基于构造函数和基于 setter 方法的 DI,然而使用有强制性依存关系的构造函数和有可选依赖关系的 setter 是一个好的做法。
现在我们从一个例子里面了解一下依赖注入的实现,我们创建两个 POJO 类,分别为 Company 类和 Person 类。
Company 类:
public class Company {
private Person person;
public Company() {}
public Company(Person person) {
System.out.println("公司有很多人!");
this.person = person;
}
public void setPerson(Person person) {
System.out.println("公司有很多人!");
this.person = person;
}
}
Person 类:
public class Person {
private String say;
public Person() {}
public Person(String say) {
System.out.println(say);
this.say = say;
}
public void setSay(String say) {
System.out.println(say);
this.say = say;
}
}
那么我们开始分别对基于构造函数和基于 setter 进行依赖注入,在 Beans.xml 文件中添加下面相应的代码块,这里我们先使用 xml 进行配置(以后讲到注解再用注解进行配置)
基于构造函数的依赖注入
<bean id="constructorCompany" class="com.tbspringDI.constructor.Company" lazy-init="true">
<constructor-arg ref="constructorPerson"></constructor-arg>
</bean>
<bean id="constructorPerson" class="com.tbspringDI.constructor.Person" lazy-init="true">
<constructor-arg type="java.lang.String" value="我是人,我说了一句人话!"></constructor-arg>
</bean>
基于setter的依赖注入
<bean id="setterCompany" class="com.tbspringDI.setter.Company" lazy-init="true">
<property name="person" ref="setterPerson"></property>
</bean>
<bean id="setterPerson" class="com.tbspringDI.setter.Person" lazy-init="true">
<property name="say" value="我是人,我说了一句人话!"></property>
</bean>
需要注意的是:基于构造函数的依赖注入需要 POJO 存在相应的构造方法,而基于 setter 的依赖注入则需要 POJO 存在相应的 setXxx() 方法。
下面用main方法进行一下测试:
public class MainAPP {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
//基于构造函数注入就将下面getBean的()里面改为constructorCompany
Company company = (Company) context.getBean("setterCompany");
}
}
控制台输出下面两句话我们就成功啦!
但为什么我们拿得是 Company 对象会输出两句话呢?
这是因为当我们从 IOC 容器中取 Company 时,IOC 帮我们先把 Person 初始化了一遍,所以我们会看到控制台会先输出一句「我是人,我说了一句话!」
除了以上两种用法外,DI 还有另外的两种两种用法:
(一)innerBean(内部 Bean):在 Beans.xml 中替换相应 Bean 即可。
<bean id="outerBeansCompany" class="com.tbspringDI.innerBeans.Company" lazy-init="true">
<property name="person">
<bean id="innerBeansPerson" class="com.tbspringDI.innerBeans.Person">
<property name="say" value="我是人,我说了一句话!"></property>
</bean>
</property>
</bean>
(二)集合注入:看个用例,我们创建一个 JavaCollection 类并在 Beans.xml 中进行配置。
JavaCollection 类:
public class JavaCollection {
private List addressList;
private Set addressSet;
private Map addressMap;
private Properties addressProp;
public List getAddressList() {
System.out.println("List Elements :" + addressList);
return addressList;
}
public void setAddressList(List addressList) {
this.addressList = addressList;
}
public Set getAddressSet() {
System.out.println("Set Elements :" + addressSet);
return addressSet;
}
public void setAddressSet(Set addressSet) {
this.addressSet = addressSet;
}
public Map getAddressMap() {
System.out.println("Map Elements :" + addressMap);
return addressMap;
}
public void setAddressMap(Map addressMap) {
this.addressMap = addressMap;
}
public Properties getAddressProp() {
System.out.println("Property Elements :" + addressProp);
return addressProp;
}
public void setAddressProp(Properties addressProp) {
this.addressProp = addressProp;
}
}
Beans.xml 中添加下列代码块:
<!-- 注入集合 -->
<bean id="javaCollection" class="com.tbspringDI.setCollection.JavaCollection">
<!-- 注入一列值,允许重复 -->
<property name="addressList">
<list>
<value>INDIA</value>
<value>Pakistan</value>
<value>USA</value>
<value>USA</value>
</list>
</property>
<!-- 注入一列值,不允许重复 -->
<property name="addressSet">
<set>
<value>INDIA</value>
<value>Pakistan</value>
<value>USA</value>
<value>USA</value>
</set>
</property>
<!-- 键值对,可以是任意类型 -->
<property name="addressMap">
<map>
<entry key="1" value="INDIA"/>
<entry key="2" value="Pakistan"/>
<entry key="3" value="USA"/>
<entry key="4" value="USA"/>
</map>
</property>
<!-- 键值对,String类型 -->
<property name="addressProp">
<props>
<prop key="one">INDIA</prop>
<prop key="two">Pakistan</prop>
<prop key="three">USA</prop>
<prop key="four">USA</prop>
</props>
</property>
</bean>
然后我们写个测试类(MainAPP)进行一下测试:
public class MainAPP {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
JavaCollection jc=(JavaCollection)context.getBean("javaCollection");
jc.getAddressList();
jc.getAddressSet();
jc.getAddressMap();
jc.getAddressProp();
}
}
输出结果如下:
我们可以看到以下区别:
- list 的列值是可以重复的;
- set 的列值是不能重复的;
- map 输出的是 Object 类型的键值对;
- Properties 输出的是 String 类型的键值对。
以上就是 Spring 依赖注入的用法,仅供学习参考。
文档信息
- 本文作者:Bin Tu
- 本文链接:https://plandocheckaction.github.io/2017/08/01/Spring3-SpringDI/
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)