Spring的IOC容器—依赖注入

来源:互联网 发布:网络上赌博的托 编辑:程序博客网 时间:2024/05/18 02:50
前面一篇博客大致讲了一下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吃东西的方法@Overridepublic void eatSomething() {System.out.println(eat.eatApple());}@Overridepublic String personInfo() {return null;} }

.Eat的实现类

/** * 大口大口吃 * @author MINGXUANYUN */public class WideMouthEat implements Eat {@Overridepublic 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 {@Overridepublic 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以松耦合的方式将它们组织在一起。各层之间不需要关心对象间的具体实现,以及如何创建,完全面向接口编程。





1 0