Spring-FrameWork Spring框架的核心概念就是“依赖注入”,什么是依赖注入?其实理解起来很简单,依赖注入其实就是框架用于连接各个应用程序的一项技术。 框架负责将你的应用程序中的各种相互依赖进行连接起来,并从应用程序代码中完全解决掉连接逻辑和对象创建。 举一个描述收银机的例子: 1.创建一个接口用来描述收银机 public interface CashRegister { public BigDecimal callculateTotalprice(ShoppingCart cart);//参数是一个购物车,方法返回是购物车中所有商品的价格. } 2.创建一个接口用来实现某商品价格查询 public interface PriceMatrix { public BigDecimal lookupPrice(Item item);//参数是某一个商品 } 3.创建CashRegister它的实现类. public class CashRegisterImpl implements CashRegister { private PriceMatrix priceMatrix = new PriceMatrixImpl(); public BigDecimal calculateTotaPrice(ShoppingCart cart) { BigDecimal total = new BigDecimal("0.0"); for(Item item:cart.getItems()) { total.add(priceMatrix.lookupPrice(item)); } return total; } } 以上实例存在三个问题: 第一个,每一个“CashRegisterImpl”的实例都会存在PriceMatrixImpl实例,也就是说创建或维护PriceMatrixImpl这个对象成本会很高。 其实就是在浪费系统的资源,最好能多个客户端共享一个实例. 第二个,同时是最为重要的问题,"CashRegisterImpl"实例很想具体的知道关于PriceMatrix实现细节.而现在它不知道自己所依赖接口的细节。 但是现在CashRegisterImpl通过自己创建了PriceMatrix对象,CashRegisterImpl已经完全的和PriceMatrixImpl对象耦合的关联在一起了。 第三个,实现类已经和CashRegisterImpl紧密的结合在一起了,很难进行单元测试。单元测试本身就是应该脱离外部资源的情况下运行. 如果要测试唯一的选择就是需要完全的运行PriceMatrixImpl.这样一来不仅会减慢单元测试而且还让我们无法控制的资源耦合在一起。 可见以上程序实现的三大不足. 要解决第一个问题,移除PriceMatrix实现类的实例,这样就可以让CashRegisterImpl对象从物理实现细节中解放出来了。更重要的是 PriceMatrixImpl对象不再CashRegisterImpl实例中,不在属于CashRegisterImpl独有,而是很容易地被所有类共享。 听说Service Locator模式不错,这个模式的优势就是:封装了获取所需要的对象的引用动作,说白点就是不用你用new关键字去创建一个对象。 这个模式会调用所对象的GETTER方法.具体方法如下。 public class CashRegisterImpl implements CashRegister { private PriceMatrix priceMatrix; public CashRegisterImpl() { priceMatrix = ServiceLocator.getPriceMatrix(); } public BigDecimal calculateTotaPrice(ShoppingCart cart) { BigDecimal total = new BigDecimal("0.0"); for(Item item:cart.getItems()) { total.add(priceMatrix.lookupPrice(item)); } return total; } } 虽然从表面上来看使用ServiceLocator,该类不用关心创建PriceMatrix实例了.但是第三个存在的问题还是解决不了。 locator方法要求不允许在测试的情况下返回一个模拟的PriceMatrix对象,允许你在实际部署中返回一个真的PriceMatrix对象, 就是说你可以创建PriceMatrix实例,但是必须要在外界的资源同步下才能测试。 这时候神秘的人物来了,就是spring框架中的"依赖注入"了,它很灵活,让你用起来得心应手。它可以有很多中注入方式。 首先说第一种注入:基于构造器注入 public class CashRegisterImpl implements CashRegister { private PriceMatrix priceMatrix; public CashRegisterImpl(PriceMatrix priceMatrix); { this.priceMatrix = priceMatrix ; } public BigDecimal calculateTotaPrice(ShoppingCart cart) { BigDecimal total = new BigDecimal("0.0"); for(Item item:cart.getItems()) { total.add(priceMatrix.lookupPrice(item)); } return total; } } 就这样,简单的获取PriceMatrix对象,看到本书上说的很恰当"你不用来管我要对象,我会主动给你创建好" 另一种注入方式:基于设置方法注入 public class CashRegisterImpl implements CashRegister { private PriceMatrix priceMatrix; public setPriceMatrix(PriceMatrix priceMatrix); { this.priceMatrix = priceMatrix ; } public BigDecimal calculateTotaPrice(ShoppingCart cart) { BigDecimal total = new BigDecimal("0.0"); for(Item item:cart.getItems()) { total.add(priceMatrix.lookupPrice(item)); } return total; } } 选择那种注入?这个其实不重要,Spring框架没有具体的要求强制用那个方法注入, 基于构造方法注入危险是:在提供不同的实例时候有可能造成构造器泛滥,随你实例增加, 各个应用程序需要不同的依赖,所以构造器的数目也在不断的增加。建议还是用设置方法注入。 这样,就解决了以上事例中的三个问题,解决了互相的依赖关系,还可以轻松的模拟出PriceMatrix 对象,做好测试。从Dependency Injection 充分的体现出了Spring框架的轻量级。