您的位置:首页 > 编程语言 > Java开发

Spring(二) 依赖注入

2016-07-27 12:38 387 查看
1. Spring的核心机制:[b]依赖注入(Dependency Injection)[/b]
Spring框架的核心功能有2个:
(1) Spring容器作为超级大工厂,负责创建、管理所有java对象,这些java对象被称为Bean。
(2) Spring容器管理容器中Bean之间的依赖关系,Spring使用一种被称为“依赖注入”的方式来管理Bean之间的依赖关系。
依赖注入是种优秀的解耦方式。让Spring的Bean以配置文件组织在一起,而不是硬编码方式耦合在一起。

1.1 理解依赖注入:
依赖注入(Dependency Injection)和控制反转(Inversion of Control, IoC)是一个意思。
使用Spring框架之后,调用者获取被依赖对象的方式由原来的主动获取,变成了被动接受(Sping框架提供)————于是Rod Johnson将这种方式称为控制反转。
从Spring容器的角度来看,Spring容器负责将被依赖对象赋值给调用者的成员变量————相当于为调用者注入它依赖的实例。所以Martine Fowler将这种方式称为依赖注入。
依赖注入有2种方式:
(1)设值注入:IoC容器使用成员变量的setter方法来注入被依赖的对象。
(2)构造注入:IoC容器使用构造器来注入被依赖的对象。

1.2 设值注入:
Spring推荐面向接口编程。不管是调用者,还是被依赖对象,都应该为之定义接口,程序应该面向它们的接口,而不是面向实现类编程,这样方便后续升级、维护。
创建2个组件的接口:
Axe.java:
package com.pmpa.ch02;

public interface Axe {
public String chop();
}
Person.java:
package com.pmpa.ch02;

public interface Person {
public void useAxe();
}


分别定义Axe和Person的实现类:
Chinese.java
package com.pmpa.ch02;

public class Chinese implements Person {

private Axe axe;

public void setAxe(Axe axe)
{
this.axe = axe;
}

@Override
public void useAxe() {
// TODO Auto-generated method stub
System.out.println("Chinese " + axe.chop());
}
}
StoneAxe.java
package com.pmpa.ch02;

public class StoneAxe implements Axe {

@Override
public String chop() {
return "石斧子砍柴慢!!";
}

}
Japanese.java
package com.pmpa.ch02;

public class Japanese implements Person {

private Axe axe;

public void setAxe(Axe axe)
{
this.axe = axe;
}

@Override
public void useAxe() {
// TODO Auto-generated method stub
System.out.println("Japanese " + axe.chop());
}

}
SteelAxe.java

package com.pmpa.ch02;

public class SteelAxe implements Axe {

@Override
public String chop() {
// TODO Auto-generated method stub
return "钢斧子砍柴快!!!";
}

}
程序没有为Person实例传入Axe实例,Axe实例由Spring在运行期间注入。

beans02.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> 
<bean id="stoneaxe" class="com.pmpa.ch02.StoneAxe"></bean>
<bean id="chinese" class="com.pmpa.ch02.Chinese">
<property name = "axe" ref="stoneaxe"></property>
</bean>

<bean id="steelaxe" class="com.pmpa.ch02.SteelAxe"></bean>
<bean id="japanese" class="com.pmpa.ch02.Japanese">
<property name = "axe" ref="steelaxe"></property>
</bean>

</beans>
测试程序BeanTest.java
package com.pmpa.ch02;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanTest {

public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/beans02.xml");
Chinese ci = ctx.getBean("chinese", Chinese.class);
ci.useAxe();

Japanese jn = ctx.getBean("japanese", Japanese.class);
jn.useAxe();
}

}


Spring IoC容器的3个基本要点:
(1)应用程序要面向接口编程。面向接口编程可以将组件之间的耦合关系提升到接口层次,从而有利于项目后期的扩展。
(2)应用程序的各个组件不再由程序主动创建,而是由Spring容器来负责产生并初始化。
(3)Spring采用配置文件或者注解来管理Bean的实现类、依赖关系,Spring容器则根据配置文件或注解,利用反射来创建实例,并为之注入依赖关系。

1.3 构造注入:
利用构造器来设置依赖关系的方式,被称为构造注入。驱动Spring在底层以反射方式执行带指定参数的构造器。在bean配置文件中,每个<constructor-arg.../>子元素代表一个构造器参数,如果<bean.../>元素包含N个<constructor-arg.../>子元素,就会驱动Spring调用带N个参数的构造器来创建对象。
<constructor-arg.../>可以指定一个name属性,name指代构造器参数名。
<constructor-arg.../>可以指定一个Index属性,用于指定该构造参数值将作为第几个构造参数值,index = "0"代表第一个构造参数值。
<constructor-arg.../>可以指定一个type属性,用于确定该属性值的数据类型。例如<constructor-arg value="23" type="int">
新建一个Person接口的实例,
Canadian.java
package com.pmpa.ch02;

public class Canadian implements Person {

private int age;
private Axe axe;

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public Axe getAxe() {
return axe;
}

public void setAxe(Axe axe) {
this.axe = axe;
}

//重点关注此处,构造方法,不能写成public void Canadian()
public Canadian (int age, Axe axe)
{
this.age  = age;
this.axe  = axe;
}

@Override
public void useAxe() {
// TODO Auto-generated method stub
System.out.println("Canadian " + "aged " + age + " " + axe.chop() );
}

}
相应beans02.xml添加内容:
<bean id="canadian" class="com.pmpa.ch02.Canadian">
<constructor-arg name="age" value="30" index ="0" ></constructor-arg>
<constructor-arg name="axe" ref="steelaxe" index="1"></constructor-arg>
</bean>
最终测试类添加:
BeanTest.java

Canadian ca = ctx.getBean("canadian", Canadian.class);
ca.useAxe();
最终结果:
Chinese 石斧子砍柴慢!!
Japanese 钢斧子砍柴快!!!
Canadian aged 30 钢斧子砍柴快!!


1.4 总结:
设值注入是先通过无参数的构造器创建一个Bean实例,然后调用对应的setter方法注入依赖关系;而构造注入则直接调用有参数的构造器,当Bean实例创建完成后,已经完成了依赖关系的注入。

两种注入方式有其各自的优势。应该以设值注入为主,构造注入为辅的注入策略。对于依赖关系无需变化的注入,尽量采用构造注入;而其他依赖关系的注入,则考虑采用设值注入。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Spring 依赖注入