spring学习笔记3

依赖注入还有另外一个响当当的名字:反转控制(IOC)

大多数的应用程序都有多个类同时协同工作来完成业务逻辑。通常情况下,每个对象自己负责获取它依赖对象的引用,这往往会产生紧耦合的代码。而应用DI时,应用对象是在创建时被赋予它们的依赖性。换言之,依赖性是被注入到应用对象中。DI最关键的优势在于松耦合。这种松耦合在于将依赖性和接口相捆绑。试想,如果一个类Foo有一个接口变量Bar,那么Bar接口是如何实现的Foo类根本无需关心,Bar有可能是一个JavaBean,一个远程web Service,一个EJB或是一个单元测试中的mock实现。

下面给出了DI的第一个例子。假设我们需要一个类来表示那些寻找圣杯(Holy Grail)的圆桌武士,我们可以这样写:

package com.springtest.knight;

 

public class RoundTableKnight {

 

       private String name;

       private HolyGrailQuest quest;

      

       public RoundTableKnight(String name) {

              this.name = name;

              quest = new HolyGrailQuest();

       }

      

       public HolyGrail embarkOnQuest() {

              return quest.emback();

       }

}

而代码中的HolyGrailQuest类表示圆桌武士寻找圣杯的行为

package com.springtest.knight;

 

public class HolyGrailQuest {

       public HolyGrailQuest() {}

      

       public HolyGrail embark() {

              HolyGrail grail = null;

              // Search for grail

              //...

              return grail;

       }

}

下面开始编写相应的单元测试代码:

package com.springtest.knight;

 

import junit.framework.TestCase;

 

public class RoundTableKnightTest extends TestCase {

       public void testEmbarkOnQuest() {

              RoundTableKnight knight = new RoundTableKnight("Bedivere");

              HolyGrail grail = knight.embarkOnQuest();

             

              assertNotNull(grail);

              assertTrue(grail.isHoly());

       }

}

上面的测试代码是有问题的。你会发现,RoundTableKnightTest测试类间接地测试了HolyGrailQuest类。如果HolyGrailQuestembark方法返回为空或是抛出GrailNotFoundException异常的话上面的测试代码就会失效了。

其实可以发现,RoundTableKnightTest类如何获得HolyGrailQuest对象是一个潜在的问题。无论通过new的方式实例化还是通过JNDI获得,我们都无法独立地来测试RoundTableKnightTest——就像前面说的,每次测试RoundTableKnightTest类都不可避免地要测试HolyGrailQuest类。这就是所谓的紧耦合。

通常使用接口隐藏具体实现来达到解耦的目的。这样具体的实现类就可以被随意替换而不影响客户类(即使用具体类的类)的使用。按照这种思路,我们来改写上面的例子。

第一步,创建一个Quest接口

package com.springtest.knight;

 

public interface Quest {

       Object embark() throws QuestFailedException;

}

然后令HolyGrailQuest类实现该接口。

package com.springtest.knight;

 

public class HolyGrailQuest implements Quest {

       public HolyGrailQuest() {}

       @Override

       public Object embark() throws QuestFailedException {

              // TODO Auto-generated method stub

              return new HolyGrail();

       }

}

同样,我们抽取出Knight作为一个接口。

package com.springtest.knight;

 

public interface Knight {

       Object embarkOnQuest() throws QuestFailedException;

}

最后我们需要这样编写RoundTableKnight来实现Knight

package com.springtest.knight;

 

public class RoundTableKnight implements Knight {

       private String name;

       private Quest quest;

      

       public RoundTableKnight(String name) {

              this.name = name;

       }

       @Override

       public Object embarkOnQuest() throws QuestFailedException {

              // TODO Auto-generated method stub

              return quest.embark();

       }

      

       public void setQuest(Quest quest) {

              this.quest = quest;

       }

}

发现不同了吗?那就是RoundTableKnight的构造函数不再负责对Quest进行实例化,而是通过一个setter方法来实现。即,RoundTableKnight不再负责获取quest对象。事实上,RoundTableKnight类将被赋予Quest对象,这就是依赖注入。

spring中最常用的就是使用XML文件来实现依赖注入。下面就为该例子创建它的xml文件:knight.xml 它负责将一个Quest对象赋予给RoundTableKnight类。

<?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-2.0.xsd">

              <bean id="quest" class="com.springtest.knight.HolyGrailQuest"/>

              <bean id="knight" class="com.springtest.knight.RoundTableKnight">

                     <constructor-arg value="spring"/>

                     <property name="quest" ref="quest"></property>

              </bean>

</beans>

写好xml文件之后现在的任务就是要加载xml文件并开始编写应用程序。

package com.springtest.knight;

 

import org.springframework.beans.factory.BeanFactory;

import org.springframework.beans.factory.xml.XmlBeanFactory;

import org.springframework.core.io.FileSystemResource;

 

public class KnightApp {

    public static void main(String[] args) {

       // TODO Auto-generated method stub

       BeanFactory factory = new XmlBeanFactory

           (new FileSystemResource("knight.xml"));

       Knight knight = (Knight)factory.getBean("knight");

       try {

           knight.embarkOnQuest();

       } catch (QuestFailedException e) {

           // TODO Auto-generated catch block

           e.printStackTrace();

       }

    }

}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值