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

Spring的IOC容器—依赖注入

2015-06-29 17:12 776 查看
前面一篇博客大致讲了一下Spring的IOC容器的原理,IOC即控制反转主要是依靠依赖注入的方式来实现的。依赖注入是指所依赖的对象不是由自己new出来的,而是用别的方式像打针似的注入进来。 其实说白了不管是控制反转还是依赖注入都说明了Spring采用动态、灵活的方式来管理各种对象。

Spring的依赖注入对调用者和被调用者几乎没有任何要求,完全支持对POJO之间依赖关系的管理。有以下几种注入方式: 

1. Setter 注入


因为对于javaBean来说,我们可以通过setter和getter方法分别改变对象和获取对象的属性。所以当前对象只要为其依赖对象所对应的属性添加setter方法,就可以通过setter方法将相应的依赖对象设置到被注入对象中。例如下面的代码:

 . Person接口

 
package com.tgb.depency;
/**
* 定义Person接口
* @author MINGXUANYUN
*
*/
public interface Person {

//定义一个吃东西的方法
public void eatSomething();

//定义一个个人信息方法
public String personInfo();
}

.Eat接口


package com.tgb.depency;
public interface Eat {
//定义一个吃苹果的方法
public String eatApple();

}

.Person的实现类

/**
* Person的实现类
* @author MINGXUANYUN
*/
public class Huohuo implements Person{

private Eat eat;
//默认的构造器
public Huohuo(){}

public Eat getEat() {
return eat;
}
public void setEat(Eat eat) {
this.eat = eat;
}

//实现Person吃东西的方法
@Override
public void eatSomething() {
System.out.println(eat.eatApple());
}

@Override
public String personInfo() {
return null;
}
}

.Eat的实现类

/**
* 大口大口吃
* @author MINGXUANYUN
*/
public class WideMouthEat implements Eat {

@Override
public String eatApple() {
return"张大嘴巴吃苹果很粗鲁的!!!";
}
}

.配置文件,将Person实例和Eat实例组织在一起

<!--Setter注入测试实例 -->
<bean id="Huohuo" class= "com.tgb.depencyimpl.Huohuo">
<property name="eat" ref="WideMouthEat"></property>
</bean>
<bean id="WideMouthEat" class="com.tgb.depencyimpl.WideMouthEat">
</bean>


从以上例子可以看出:Spring将bean与bean之间的依赖关系放到配置文件里管理,而不是写在代码里。通过配置文件,Spring精确的为每个bean注入每个属性。<bean>中的name属性是class属性的一个别名,class属性指真正的实现类(类的全名)。Spring自动接管每个bean里的 property元素定义。Spring再执行无参数的构造器,创建默认的bean后,调用对应的setter方法为程序注入属性值。

.主程序

public class SetterTest {

public static void main(String[] args) {
//实例化Spring的上下文
ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml");
//强制转换接口类型
Person person = (Person) ctx.getBean("Huohuo");
//执行Person的eatSomething方法
person.eatSomething();
}

}


.运行结果输出 :

                    
张大嘴巴吃苹果很粗鲁的!!!

说明: 主程序调用person.eatSomething方法,该方法方法体里需要有Eat的实例,但主程序里并没有任何地方为Person实例传入Eat实例,Eat实例是由Spring在运行期间动态注入的。Person实例不需要了解Eat实例的具体实现和创建过程。程序运行到Eat实例的时候,Spring自动创建Eat实例,然后注入给它的调用者,Person实例运行到需要Eat实例的时候,自动产生Eat实例。

这样有什么好处呢?如果我们需要另一个Eat实现类来为Person类使用。Person和其实现类都无需改变。只需要增加一个Eat的实现类,并在配置文件中配置就可以。

例如,增加Eat实现类ChewslowlyEat

import com.tgb.depency.Eat;

public class ChewslowlyEat implements Eat {
@Override
public String eatApple() {
return "细嚼慢咽淑女的典范!!";
}
}


修改配置文件:

<bean id="Huohuo" class= "com.tgb.depencyimpl.Huohuo">
   <property name="eat" ref="ChewslowlyEat"></property>
</bean>
<bean id="ChewslowlyEat" class="com.tgb.depencyimpl.ChewslowlyEat"></bean>


输出结果:

    细嚼慢咽淑女的典范!!

2. 构造器注入

  指被注入对象通过在其构造函数中声明依赖对象的参数列表。

.定义一个Person实现类,用于构造器注入

/**
* 构造器注入测试
* @author MINGXUANYUN
*/
public class Yunyun implements Person{
    private String userName;
    private String kind;
    private Eat eat;
    //默认构造方法
    public Yunyun(){};
    //构造注入所需的带参数构造器
    public Yunyun(Eat eat,String userName,String kind){
        this.eat = eat;
        this.userName = userName;
        this.kind = kind;
    }
    @Override
    public String personInfo() {
        return userName + "永远" + kind +"岁" + "----" + eat.eatApple();
    }
    @Override
    public void eatSomething() {
        // TODO Auto-generated method stub    
    }
}


在构造Yunyun实例时,创建三个成员变量userName、kind和对象类型的eat。但是并没有设置setter方法。在构造Person实例时,Spring为Person实例注入所依赖的Eat实例并且为两个成员变量赋值。构造注入的配置文件如下:

.xml配置文件

<!--构造器注入配置实例 -->
        <bean id="Yunyun" class= "com.tgb.depencyimpl.Yunyun">
        <constructor-arg index="0" ref="ChewslowlyEat"></constructor-arg>
        <constructor-arg index="1">  
            <value>朱火云 </value>  
          </constructor-arg>  
          <constructor-arg index="2">  
            <value>18</value>  
          </constructor-arg>
        </bean>  
        <bean id="ChewslowlyEat" class="com.tgb.depencyimpl.ChewslowlyEat"/>


在配置文件中,不用<property>的形式,而是使用<constructor-arg>标签。ref属性指向其它<bean>标签的name属性。由于我们可能传入多个类型一致的构造参数。所以可以用type和index确定我们使用的哪一个构造函数。

.主程序

public class ConstructorTest {

public static void main(String[] args) {
String fileName = "bean.xml";
ApplicationContext ac = new FileSystemXmlApplicationContext(fileName);
// 取得一个实例
Yunyun yunyun =  (Yunyun) ac.getBean("Yunyun");
System.out.println(yunyun.personInfo());
}
}


输出结果:

             
朱火云 永远18岁细嚼慢咽淑女的典范!!

3.静态工厂方法注入


    指通过调用静态工厂的方法来获取自己需要的对象。

.定义一个UserDao类

public class UserDao {
public static UserDao getInstance(){
return new UserDao("static factory method");
}

private String name="";
public UserDao(String name){
this.name = name;
}

public void create(){
System.out.println("create user from-" + name);
}
}


.定义一个UserManager类

import com.tgb.depency.UserDao;

public class UserManager {
//注入UserDao对象
private UserDao userDao;
public void createUser(){
userDao.create();
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public UserDao getUserDao() {
return userDao;
}
}


.xml配置文件

<!-- 静态工厂方法注入 -->
<bean name="userManager" class="com.tgb.depencyimpl.UserManager">
<property name="userDao" ref="userDao"></property>
</bean>
<bean name="userDao" class="com.tgb.depency.UserDao" factory-method="getInstance">
</bean>


factory-menthod定义了userDao 。Bean使用UserDao类的getInstance方法来创建自己的实例。

.主程序

public class StaticFactoryTest {

public static void main(String[] args) {
String fileName = "bean.xml";
ApplicationContext ac = new FileSystemXmlApplicationContext(fileName);
UserManager userManager = (UserManager) ac.getBean("userManager");
userManager.createUser();
}
}

输出结果:

                create user from-static factory method

总结:我们原来学三层的时候,UI层调用BLL、BLL调用DAO层。各层与各层之间虽然抽象出了接口层,调用接口。但是在new的时候指向的还是具体的实现。而现在Spring有效的管理各层之间对象的调用。 不管是Action调用Services对象,还是Services调用Dao对象,Spring以松耦合的方式将它们组织在一起。各层之间不需要关心对象间的具体实现,以及如何创建,完全面向接口编程。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: