中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> 程序开发 > 编程语言 > Java > 综合文章
用AspectJ和Spring进行依赖项插入
作者:JiaJia 时间:2006-09-20 08:02 出处:ccidnet.com 责编:月夜寒箫
              摘要:用AspectJ和Spring进行依赖项插入

基于接口的插入

迄今为止,我使用了 Spring 容器读取的 bean 定义来确定对象的依赖项。这个方案的一个变体采用合约接口,由客户端声明它的要求。假设前一节的 Account 实体要求访问AccountOperationValidationService。我可以声明一个接口,如清单 4 所示:

清单 4. 客户端接口

 

public interface AccountOperationValidationClient {
            public void setAccountOperationValidationService(
            AccountOperationValidationService aValidationService);
            }

现在,需要访问 AccountOperationValidationService 的对象必须实现这个接口,并把自己声明为客户。使用与前一节开发的方面类似的方面,我可以匹配实现这个接口的客户对象的所有初始化连接点。由它负责第一个代理职责:确定什么时候需要配置对象。第二个职责在接口中被明确表达:必须满足的依赖项是验证服务依赖项。我将用一个方面插入所有客户验证服务的依赖项。方面得到合适服务的最简单方法就是把服务插入到方面自身!清单 5 显示了一个示例:

清单 5. 服务插入器方面

 

/**
            * ensure that all clients of
            the account validation service
            * have access to it
            */
            public aspect
            AccountOperationValidationServiceInjector
            {
            private AccountOperationValidationService
            service;
            /**
            * the aspect itself is
            configured via Spring DI
            */
            public void setService
            (AccountOperationValidationService aService)
            {
            this.service = aService;
            }
            /**
            * the creation of any object
            that is a client of the
            * validation service
            */
            pointcut clientCreation
            (AccountOperationValidationClient aClient) :
            initialization
            (AccountOperationValidationClient+.new(..))
            &&
            this(aClient);
            /**
            * inject clients when they are created
            */
            after(AccountOperationValidationClient aClient)
            returning :
            clientCreation(aClient)
            {
            aClient.setAccountOperationValidationService
            (this.service);
            }
            }

这个解决方案提供了两级控制。服务本身实际的定义是在 Spring 的配置文件中提供的,就像清单 6 中的 XML 片段示例一样:

清单 6. 服务插入器配置

 

<beans>
            <bean name=
            "AccountOperationValidationServiceInjector"
            class=
            "org.aspectprogrammer.dw.
            AccountOperationValidationServiceInjector"
            factory-method="aspectOf">
            <property name="service">
            <ref bean=
            "AccountOperationValidationService"/>
            </property>
            </bean>
            <bean name=
            "AccountOperationValidationService"
            class="org.aspectprogrammer.dw.
            DefaultAccountOperationValidationService">
            </bean>
            </beans>

服务的客户只需要实现 AccountOperationValidationClient 接口,那么就会自动用 Spring 定义的服务的当前实例对它们进行配置。

重复插入

迄今为止,我介绍的解决方案都是在对象初始化之后立即配置对象。但是,在某些情况下,客户需要与之协调的对象在运行的时候变化。例如,通过与系统进行交互,销售团队可以动态地为在线预订应用程序修改报价策略和座位分配策略。与报价策略和座位分配策略交互的预订服务需要的策略实现,应当是预订时的实现,而不是预订服务第一次初始化的时候实现的版本。在这种情况下,可以把依赖项的插入延迟到客户第一次需要它的时候,并在每次引用依赖项的时候,将依赖项的最新版本重新插入客户。

这个场景的基本技术包括字段级插入或 getter 方法覆盖。在进入示例之前,我要再次强调:我要介绍的插入技术所面向的对象,是在 Spring 容器的控制之外 创建的。对于 Spring 创建的对象,Spring 容器已经提供了解决这些需求的简单机制。

字段级插入

在下面的示例中,可以看出如何为延迟插入或重复插入应用字段级插入。字段的 get 连接点让我可以确定什么时候进行插入,而字段类型可以确定要插入的依赖项。所以,如果客户声明了这样的一个字段:

 

private PricingStrategy pricingStrategy;

而在客户的方法中,发现了下面的代码

 

this.pricingStrategy.price(.....);

那么代码在运行时的执行会形成 pricingStrategy 字段的 get() 连接点,我可以用它插入当前报价策略实现,如清单 7 所示:

清单 7. 字段级插入示例

 

public aspect PricingStrategyInjector
            {
            private PricingStrategy currentPricingStrategy;
            public void setCurrentPricingStrategy
            (PricingStrategy aStrategy)
            {
            this.currentPricingStrategy = aStrategy;
            }
            /**
            * a client is trying to access
            the current pricing strategy
            */
            pointcut pricingStrategyAccess() :
            get(PricingStrategy *) &&
            !within(PricingStrategyInjector);
            // don’t advise ourselves!
            /**
            * whenever a client accesses a
            pricing strategy field, ensure they
            * get the latest...
            */
            PricingStrategy around()
            : pricingStrategyAccess()
            {
            return this.currentPricingStrategy;
            }
            }

服务定位策略

重复插入的一个替代就是用更常规的技术,用服务定位策略技术实现插入客户。例如:

 

public interface PricingStrategyLocator
            {
            PricingStrategy
            getCurrentPricingStrategy();
            }

虽然代价是定义一个额外接口,还会使客户代码更长一些,但是这项技术对于代码清晰性来说具有优势。

结束语

在这篇文章中,我把依赖项插入看作对象和对象执行的环境之间的合约。对象不愿意外出寻找自己需要的资源、要协作的合作伙伴或者使用的服务。相反,对象提供了一种机制,允许把这些依赖项提供给它。然后,在对象需要依赖项之前,执行环境负责把对象需要的所有依赖项提供给它。

我讨论了依赖项插入解决方案的四个关键职责,这些是代理代表对象获取依赖项时必须解决的问题。最后,我介绍了满足这些需求的许多不同的技术。显然,如果能够 用 Spring 容器初始化并配置对象,那么就应当这么做。对于在 Spring 容器的控制之外创建的对象,例如一些使用非单体实例化模型的域对象或方面,我推荐使用 @SpringConfigured 标注或类似的东西。这项技术让您可以把全部配置信息完全转移到外部的 Spring 配置文件中。

关闭本页
 
首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
Copyright ©2005-2008 chinaitpower.com All rights reserved. www.chinaitpower.com 版权所有