标签:style blog http io ar color os 使用 sp
前面说过IoC容器实现控制反转的核心就是DI——依赖注入。对象之间的依赖关系无非会通过以下几种方式来实现:构造器的参数、工厂方法的参数,或给由构造函数或者工厂方法创建的对象设置属性。所以,IoC容器的工作就是创建bean时注入那些依赖关系。
相对于由bean自己来控制其实例化、直接在构造器中指定依赖关系或则类似服务定位器(ServiceLocator)模式这3种自主控制依赖关系注入的方法来说,控制从根本上发生了倒转,这也正是控制反转(Inversionof Control, IoC) 名字的由来。
应用DI原则后,代码将更加清晰。而且当bean自己不再担心对象之间的依赖关系(以及在何时何地指定这种依赖关系和依赖的实际类是什么)之后,实现更高层次的松耦合将更加容易。
下面主要介绍DI的两种注入方式,即Setter注入和 构造器注入:
通过调用无参构造器或无参static工厂方法实例化bean之后,调用该bean的setter方法,即可实现基于setter的DI:
package com.bjpowernode.spring.manager;
import com.bjpowernode.spring.dao.UserDao;
import com.bjpowernode.spring.dao.UserDao4MysqlImpl;
import com.bjpowernode.spring.dao.UserDao4OracleImpl;
public class UserManagerImpl implements UserManager {
private UserDao userDao;
//无参构造器
public UserManagerImpl() {
super();
}
//setter方式注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void addUser(String username, String password) {
//原始的方式--由我们的程序负责服务(对象)管理
//UserDao userDao = new UserDao4MysqlImp();
//UserDao userDao = new UserDao4OracleImpl();
userDao.addUser(username, password);
}
}
配置--applicationContext.xml:
<?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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<bean id="UserDao4MysqlImpl" class="com.bjpowernode.spring.dao.UserDao4MysqlImpl"/>
<bean id="UserDao4OracleImpl" class="com.bjpowernode.spring.dao.UserDao4OracleImpl"/>
<bean id ="UserManager" class="com.bjpowernode.spring.manager.UserManagerImpl">
<!--
<constructor-arg ref="UserDao4OracleImpl"/>
-->
<property name="userDao" ref="UserDao4OracleImpl"/>
</bean>
</beans>
基于构造器的DI通过调用带参数的构造器来实现,每个参数代表着一个协作者。此外,还可通过给静态工厂方法传参数来构造bean:
package com.bjpowernode.spring.manager;
import com.bjpowernode.spring.dao.UserDao;
import com.bjpowernode.spring.dao.UserDao4MysqlImpl;
import com.bjpowernode.spring.dao.UserDao4OracleImpl;
public class UserManagerImpl implements UserManager {
private UserDao userDao;
//构造方法方式注入
public UserManagerImpl(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void addUser(String username, String password) {
//原始的方式--由我们的程序负责服务(对象)管理
//UserDao userDao = new UserDao4MysqlImp();
//UserDao userDao = new UserDao4OracleImpl();
userDao.addUser(username, password);
}
}
配置--applicationContext.xml:
<?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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<bean id="UserDao4MysqlImpl" class="com.bjpowernode.spring.dao.UserDao4MysqlImpl"/>
<bean id="UserDao4OracleImpl" class="com.bjpowernode.spring.dao.UserDao4OracleImpl"/>
<bean id ="UserManager" class="com.bjpowernode.spring.manager.UserManagerImpl">
<constructor-arg ref="UserDao4OracleImpl"/>
<!--
<property name="userDao" ref="UserDao4OracleImpl"/>
-->
</bean>
</beans>
无论是对象、还是属性,只要给入口(set方法),Spring就可以注入对象或属性。
Spring能够以String类型提供值转换成各种内置类型,比如int、long、String、boolean等。实例如下:
【class Bean1】
package com.bjpowernode.spring;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Bean1 {
private String strValue;
private int intValue;
private List listValue;
private Set setValue;
private String[] arrayValue;
private Map mapValue;
public String getStrValue() {
return strValue;
}
public void setStrValue(String strValue) {
this.strValue = strValue;
}
public int getIntValue() {
return intValue;
}
public void setIntValue(int intValue) {
this.intValue = intValue;
}
public List getListValue() {
return listValue;
}
public void setListValue(List listValue) {
this.listValue = listValue;
}
public Set getSetValue() {
return setValue;
}
public void setSetValue(Set setValue) {
this.setValue = setValue;
}
public String[] getArrayValue() {
return arrayValue;
}
public void setArrayValue(String[] arrayValue) {
this.arrayValue = arrayValue;
}
public Map getMapValue() {
return mapValue;
}
public void setMapValue(Map mapValue) {
this.mapValue = mapValue;
}
}
【配置--applicationContext.xml】
<?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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<bean id="bean1" class="com.bjpowernode.spring.Bean1">
<property name="strValue" value="Hello_Spring"/>
<!--
<property name="intValue" value="123"/>
-->
<property name="intValue">
<value>456</value>
</property>
<property name="listValue">
<list>
<value>list1</value>
<value>list2</value>
<value>list3</value>
</list>
</property>
<property name="setValue">
<set>
<value>set1</value>
<value>set2</value>
<value>set3</value>
</set>
</property>
<property name="arrayValue">
<list>
<value>array[0]</value>
<value>array[1]</value>
<value>array[2]</value>
</list>
</property>
<property name="mapValue">
<map>
<entry key="k1" value="v1"/>
<entry key="k2" value="v1"/>
<entry key="k3" value="v1"/>
</map>
</property>
</bean>
</beans>
【测试用例—InjectionTest】
需要引入测试用例的jar包-- junit.jar,目录:spring-framework\lib\junit\ junit.jar
package test;
import junit.framework.TestCase;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.bjpowernode.spring.Bean1;
public class InjectionTest extends TestCase {
private BeanFactory factory;
@Override
protected void setUp() throws Exception {
factory = new ClassPathXmlApplicationContext("applicationContext.xml");//读取一个配置文件
}
@Override
protected void tearDown() throws Exception {
//结束时需要释放的资源
}
public void testInjection1(){
Bean1 bean1=(Bean1)factory.getBean("bean1");
System.out.println("bean1.strValue="+ bean1.getStrValue());
System.out.println("bean1.IntValue="+ bean1.getIntValue());
System.out.println("bean1.listValue="+ bean1.getListValue());
System.out.println("bean1.setValue="+ bean1.getSetValue());
System.out.println("bean1.arrayValue="+ bean1.getArrayValue());
System.out.println("bean1.mapValue="+ bean1.getMapValue());
System.out.println("bean1.dateValue="+ bean1.getDateValue());
}
}
输出结果:
可以看到Spring容器已将值注入到了Bean1的属性中。
上面提到了,Spring能够以String类型提供值转换int、long、String、boolean等兼容类型,但它无法直接转换为Date等不兼容的类型,这样的转换需要手动写属性编辑器来完成。
例如上面的例子中,给Bean1中加一个Date类型的属性,如下:
private Date dateValue;
public Date getDateValue() {
return dateValue;
}
public void setDateValue(Date dateValue) {
this.dateValue = dateValue;
}
那么直接在Spring配置中单纯的配置如下的属性映射,是会报类型转换错误的:
<property name="dateValue" value="2014-11-27"/>
还需要手动写一个属性编辑器,来完成字符串到Date类型之间的转换,如下【class UtilDatePropertyEditor】:
package com.bjpowernode.spring;
import java.beans.PropertyEditorSupport;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* java.util.Date属性编辑器
*/
public class UtilDatePropertyEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
System.out.println("---UtilDatePropertyEditor.setAsText()--->"+text);
try {
Date date = new SimpleDateFormat("yyyy-MM-dd").parse(text);
this.setValue(date);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new IllegalArgumentException();
}
}
}
然后需要将属性编辑器注入到CustomEditorConfigurer类的customEditors属性(为Map类型)中。再添加一个Spring的核心配置文件【applicationContext-editor.xml】:
<?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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<bean id="customEditors" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date">
<bean class="com.bjpowernode.spring.UtilDatePropertyEditor"/><!-- 内部bean(不用id属性) -->
</entry>
</map>
</property>
</bean>
<!--
<bean id="utilDatePropertyEditor" class="com.bjpowernode.spring.UtilDatePropertyEditor"></bean>
-->
</beans>
然后更改测试用例即可,主要是构造BeanFactory时参数中添加刚添加的另一个Spring的配置文件:
String[] configLocations = new String[]{"applicationContext.xml","applicationContext-editor.xml"};
//factory = new ClassPathXmlApplicationContext("applicationContext.xml");//读取一个配置文件
factory = new ClassPathXmlApplicationContext(configLocations);//读取多个配置文件
然后就可以正确地将字符串注入到Date类型的属性中。
由于大量的构造器参数可能使程序变得笨拙,特别是当某些属性是可选的时候。因此通常情况下,Spring开发团队提倡使用setter注入。而且setter DI在以后的某个时候还可将实例重新配置(或重新注入)(JMX MBean就是一个很好的例子)。
尽管如此,构造器注入,在某些特定的场景下还是很受青睐的。对于注入类型的选择并没硬性的规定。根据实际的业务场景,只要能适合你的应用,无论使用何种类型的DI都可以。
标签:style blog http io ar color os 使用 sp
原文地址:http://blog.csdn.net/wang379275614/article/details/41607153