Leo Wang's Notepad

DI

理解Spring中的DI和AOP

问题的提出

Spring中的依赖注入(DI)为何而生?

下面这篇日语文章提到,所有的Web应用都需要考虑到下面三个问题。

Spring MVCの概要を理解する

1)对象的生命周期问题。

假设你用Servlet来接收用户的访问请求,有一个用户需要访问一个页面,你就需要一个线程来负责处理这个请求,并调用某个业务逻辑(比如调用一个UserService的实例)。如果处理不当,每新增一个用户就实例化一个业务逻辑(new一个UserService的实例),随着访问用户的增多,就会给系统带来大量垃圾回收负担,以及内存消耗的问题。为了防止这种情况发生,就需要把业务逻辑的部分设计为Singleton的,这样就不会每次都新增一个实例。

2)松耦合问题。

为了实现Web程序中的松耦合,即让一个类与另一个类不是那么的紧密结合,通常需要接口(Interface)来实现。但是单存的利用Interface并不能实现松耦合。还需要利用一些技巧,比如Factory Method等设计模式。

3)技术细节的隐藏。

当你写一个User或者SalesOrder类的时候,你希望专注于自己的业务逻辑,比如创建用户,删除用户,创建订单,删除订单这些具体的业务。如果你在这些类中再加上访问记录(log)处理,就会明显的影响你程序的可读性。因为本质上log处理和你的业务逻辑没有什么联系,两者混杂在一起就会让人看起来比较头大。还有一些异常处理类的逻辑也会产生同样的问题。你怎样才能把这些和真正的业务逻辑无关的逻辑分离出去?

问题的回答

Spring给出的解决方案是这样的。

1)对象的生命周期问题。=>DI

2)松耦合问题。 => DI

3)技术细节的隐藏。=>AOP

首先Spring是怎么实现DI的呢,是通过DI Container来实现的。

在没有使用DI的Web应用中,Controller用到Service的时候,会生成(new)一个,Service用到DAO的时候,也是同样的生成(new)一个。

no DI

而使用了DI的Spring,则将实例化的工作全部交给了DI Container去做。

Controller中仅仅声明了Service接口的一个属性,具体的实现(new)没有去做,同样Service中也只是声明了一个DAO接口的一个属性,也没有去实现(new)。当需要实例的时候,就让DI Container根据配置去找到合适的类去实例化相应的接口属性。

DI

而用Spring写成的Web程序,其处理顺序可以用下图来表示

Spring Flow

  1. Dispatcher Servlet接收用户访问请求
  2. Dispatcher Servlet利用HandlerMapping取得URL所对应的Controller对象
  3. Controller来实行业务逻辑,调用Service对象和DAO对象得到业务数据,并把数据放到Model中。并返回一个View的名字,希望把数据显示到该View上。
  4. Dispatcher Servlet得到View的名字后,调用View Resolver来得到相应的View对象。
  5. Dispatcher Servlet把View对象生成为一个画面(View),画面包含Model对象中的数据,然后把这个View返回给用户(response)。用户的浏览器把这个画面呈献给用户。

 …