基于接口的插入
迄今为止,我使用了 Spring 容器读取的 bean 定义来确定对象的依赖项。这个方案的一个变体采用合约接口,由客户端声明它的要求。假设前一节的 Aclearcase/" target="_blank" >ccount 实体要求访问AccountOperationValidationService。我可以声明一个接口,如清单 4 所示:
清单 4. 客户端接口
现在,需要访问 AccountOperationValidationService 的对象必须实现这个接口,并把自己声明为客户。使用与前一节开发的方面类似的方面,我可以匹配实现这个接口的客户对象的所有初始化连接点。由它负责第一个代理职责:确定什么时候需要配置对象。第二个职责在接口中被明确表达:必须满足的依赖项是验证服务依赖项。我将用一个方面插入所有客户验证服务的依赖项。方面得到合适服务的最简单方法就是把服务插入到方面自身!清单 5 显示了一个示例:
清单 5. 服务插入器方面
这个解决方案提供了两级控制。服务本身实际的定义是在 Spring 的配置文件中提供的,就像清单 6 中的 XML 片段示例一样:
清单 6. 服务插入器配置
服务的客户只需要实现 AccountOperationValidationClient 接口,那么就会自动用 Spring 定义的服务的当前实例对它们进行配置。
重复插入
迄今为止,我介绍的解决方案都是在对象初始化之后立即配置对象。但是,在某些情况下,客户需要与之协调的对象在运行的时候变化。例如,通过与系统进行交互,销售团队可以动态地为在线预订应用程序修改报价策略和座位分配策略。与报价策略和座位分配策略交互的预订服务需要的策略实现,应当是预订时的实现,而不是预订服务第一次初始化的时候实现的版本。在这种情况下,可以把依赖项的插入延迟到客户第一次需要它的时候,并在每次引用依赖项的时候,将依赖项的最新版本重新插入客户。
这个场景的基本技术包括字段级插入或 getter 方法覆盖。在进入示例之前,我要再次强调:我要介绍的插入技术所面向的对象,是在 Spring 容器的控制之外 创建的。对于 Spring 创建的对象,Spring 容器已经提供了解决这些需求的简单机制。
字段级插入
在下面的示例中,可以看出如何为延迟插入或重复插入应用字段级插入。字段的 get 连接点让我可以确定什么时候进行插入,而字段类型可以确定要插入的依赖项。所以,如果客户声明了这样的一个字段:
而在客户的方法中,发现了下面的代码
那么代码在运行时的执行会形成 pricingStrategy 字段的 get() 连接点,我可以用它插入当前报价策略实现,如清单 7 所示:
清单 7. 字段级插入示例
服务定位策略
重复插入的一个替代就是用更常规的技术,用服务定位策略技术实现插入客户。例如:
虽然代价是定义一个额外接口,还会使客户代码更长一些,但是这项技术对于代码清晰性来说具有优势。
结束语
在这篇文章中,我把依赖项插入看作对象和对象执行的环境之间的合约。对象不愿意外出寻找自己需要的资源、要协作的合作伙伴或者使用的服务。相反,对象提供了一种机制,允许把这些依赖项提供给它。然后,在对象需要依赖项之前,执行环境负责把对象需要的所有依赖项提供给它。
我讨论了依赖项插入解决方案的四个关键职责,这些是代理代表对象获取依赖项时必须解决的问题。最后,我介绍了满足这些需求的许多不同的技术。显然,如果能够 用 Spring 容器初始化并配置对象,那么就应当这么做。对于在 Spring 容器的控制之外创建的对象,例如一些使用非单体实例化模型的域对象或方面,我推荐使用 @SpringConfigured 标注或类似的东西。这项技术让您可以把全部配置信息完全转移到外部的 Spring 配置文件中。
(T117)