学习Spring框架系列(一):通过Demo阐述IoC和DI的优势所在

  • Spring框架最核心东西便是大名鼎鼎的IoC容器,主要通过DI技术实现。下面我通过Demo的演变过程,对比学习耦合性代码,以及解耦和的过程,并深入理解面向接口编程的真正内涵。

     

    这个例子包括如下几个类:

    • 实体类:Book,有名称、作者等属性
    • BookFinder接口,定义了findAll()方法
    • BookLister接口,定义了findBooks(String name)方法,以书名作为参数,并返回Book[]数组作为查找的结果
    • 以及一个测试客户端BookClient,调用BookLister,来获取所需要的数据

     

    Book.java

    public class Book {
    private String name;
    private String author;
    /**
     * @return Returns the author.
     */
    public String getAuthor() {
    return author;
    }
    /**
     * @param author The author to set.
     */
    public void setAuthor(String author) {
    this.author = author;
    }
    //other getters/setters…
    }


     

    BookFinder

    • BookFinder接口
      public interface BookFinder {
      public List findAll();
      }
       
      SimpleBookFinderImpl
      public class SimpleBookFinderImpl implements BookFinder{
      /**
       * @see com.bjpowernode.spring.BookFinder#findAll()
       */
      public List findAll() {
      List books = new ArrayList();
      for(int i=0; i<20; i++){
      Book book = new Book();
      book.setName("book"+i);
      book.setAuthor("author"+i);
      books.add(book);
      }
      return books;
      }
      }


     

    BookLister

    • BookList接口
      public interface BookLister{
      public Book[] findBooks(String name);
      }
      BookListerImpl实现代码
      public class BookListerImpl implements BookLister {
      BookFinder finder;
      public BookListerImpl() {
      finder = new SimpleBookFinderImpl();
      }
      public Book[] findBooks(String name){
      List books = finder.findAll();
      for (Iterator iter = books.iterator(); iter.hasNext();) {
      Book book = (Book) iter.next();
      if(!book.getName().equals(name)){
      iter.remove();
      }
      }
      return (Book[])books.toArray(new Book[books.size()]);
      }


     

    Spring配置ApplicationContext.xml及客户调用代码

    • Spring配置:

    <bean id="bookLister" class="com.bjpowernode.spring.BookListerImpl“/>

     

    • 客户调用代码

    public static void main(String[] args) {
    BeanFactory beanFactory = new ClassPathXmlApplicationContext("applicationContext.xml");
    BookLister bl = (BookLister)beanFactory.getBean("bookLister");
    Book[] books = bl.findBooks("book3");
    if(books != null){
    for(int i=0; i<books.length; i++){
    System.out.println("书《"+books[i].getName()+"》的作者是:"+books[i].getAuthor());
    }
    }
    }


     

    同样的问题:需求变更?

    • 现在,我们需要的不再是一个简单的BookFinder,我们需要的是一个能从本地文件系统中读取文件,并分析其中所包含的Book的内容,将其结果返回
    • 因为我们遵守了面向接口编程,所以,我们只需要提供第二个实现即可

     

    FileBookFinderImpl –从文件系统读取Book的信息

    public class FileBookFinderImpl implements BookFinder {
    public List findAll() {
    String file = “d:/test.txt”;
    List books = new ArrayList();
    try {
    BufferedReader in
           = new BufferedReader(new FileReader(file));
    String line = null;
    while( (line = in.readLine()) != null)
    {
    String[] sp = line.split(";");
    if(sp.length == 2){
    …          
    Book book = new Book();
    book.setName(sp[0]);
    book.setAuthor(sp[1]);
    books.add(book);
    }
    }
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    } catch (IOException e) {
    e.printStackTrace();
    }
    return books;
    }
    }


     

    现在需要做什么?

    • 我们的客户代码调用BookLister
    • BookLister如何调用BookFinder?下面是以前初始化BookFinder的代码:

    public BookListerImpl() {

    finder = newSimpleBookFinderImpl();

    }

    • 现在,我们必须改动这段代码:

    public BookListerImpl() {

    finder = newFileBookFinderImpl();

    }

    • 看出问题来了吗?

     

    严重违反面向对象的设计原则

    • BookLister接口的实现类严重依赖于BookFinder接口的实现类,这就是问题所在!
    • 我们必须在BookLister的实现类和BookFinder的实现类之间进行解偶,即解除它们之间的实现类耦合关系(依赖!)
    • 我们需实现以下目标:
      • BookLister的实现类BookListerImpl不应该依赖于特定的BookFinder接口的实现类(比如SimpleBookFinderImplFileBookFinderImpl
      • BookLister的实现类,应该仅仅依赖于BookFinder接口,它不应该跟具体的功能需求实现相
      • 总之,我们不应该让BookListerBookFinder的实现类之间互相耦合!

     

    Spring让一切变得轻而易举

    创建setter方法,为注入做好准备

    • BookListerImpl中定义一个setter方法

    public void setFinder(BookFinder finder) {

    this.finder = finder;

    }

    • BookListerImpl构造器中的new语句注释掉

    public BookListerImpl() {

    //finder = new FileBookFinderImpl();

    }

    • Spring去关心那些烦人的依赖关系吧!

     

    Spring配置文件:ApplicationContext.xml

    • 添加BookFinder定义

    <bean id="fileBookFinder" class="com.bjpowernode.spring.impl.FileBookFinderImpl“/>

    • 修改BookLister定义的配置

    <bean id="bookLister" class="com.bjpowernode.spring.BookListerImpl">

    <property name="finder" ref=“fileBookFinder" />

    </bean>

    • 以上配置,即指定了BookListerImplFileBookFinderImpl之间的依赖关系,这种依赖关系,被放到了配置文件中,这样,只要需求有变更,只需要修改这种依赖关系即可,java代码本身不用任何变更

     

    简单配置后面隐藏的内涵

    • 控制反转(Inversion of ControlIoC)与依赖注入(Dependency Injection)
    • 本来是由应用程序管理的对象之间的依赖关系,现在交给了容器管理,就叫“控制反转”或“依赖注入”。即我们需要做的事情交给了IoC容器,SpringIoC容器主要使用DI方式实现的。不需要主动查找,对象的查找、定位和创建全部由容器管理
    • 注入,其实就是个赋值的过程,只是当我们使用时,容器已经为我们赋值好了。Spring默认在创建BeanFactory时,将配置文件中所有的对象实例化并进行注入(注入时间,可以通过default-lazy-init属性进行设置)。
    • 分析IoC容器的操作流程

    实例化类。实例化fileBookFinderBookListerImpl

    根据property标签赋值。把FileBookFinderImpl对象赋值BookListerImpl对象中的finder属性。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值