J2EE中使用Spring AOP框架和EJB组件(4)

J2EE中使用Spring AOP框架和EJB组件(4)

[@more@]

完成这种实现并测试(在容器外部!)之后,就可以把它与其他组件进行集成。传统的做法是向TradeManager2Impl添加一些代码,以便检查getPrice()方法返回的值。这会使测试的次数至少增加一倍,而且要求为每个测试用例设定附加的先决条件。然而,如果使用Spring AOP框架,就可以更漂亮地完成这项工作。您可以实现一条通知,如果初始的TradeManager没有返回所请求符号的值,该通知将使用YahooFeed组件来获取价格(在这种情况下,它的值是null,但是也可能会得到一个UnknownSymbol异常)。

要把通知应用到具体的方法,需要在Spring的bean配置中声明一个Advisor。有一个方便的类叫做NameMatchMethodPointcutAdvisor,它允许通过名称选择方法,在本例中还需要一个getPrice方法:

<bean id="yahooFeed" class="org.javatx.spring.aop.YahooFeed"/>

<bean id="foreignTradeAdvisor"

class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">

<property name="mappedName" value="getPrice"/>

<property name="advice">

<bean class="org.javatx.spring.aop.ForeignTradeAdvice">

<constructor-arg index="0" ref="yahooFeed"/>

</bean>

</property>

</bean>

正如您所看到的,上面的advisor指派了一个ForeignTradeAdvice给getPrice()方法。针对通知类,Spring AOP框架使用了AOP Alliance API,这意味着环绕通知的ForeignTradeAdvice应该实现MethodInterceptor接口。例如:

public class ForeignTradeAdvice implements MethodInterceptor {

private TradeManager tradeManager;

public ForeignTradeAdvice(TradeManager manager) {

this.tradeManager = manager;

}

public Object invoke(MethodInvocation invocation) throws Throwable {

Object res = invocation.proceed();

if(res!=null) return res;

Object[] args = invocation.getArguments();

String symbol = (String) args[0];

return tradeManager.getPrice(symbol);

}

}

上面的代码使用invocation.proceed()调用了一个原始的组件,而且如果它返回null,它将调用另一个在通知创建时作为构造函数参数注入的tradeManager。参见上面foreignTradeAdvisor bean的声明。

现在可以把在Spring的bean配置中定义的tradeManager重新命名为baseTradeManager,然后使用ProxyFactoryBean把tradeManager声明为一个代理。新的baseTradeManager将成为一个目标,我们将使用上面定义的foreignTradeAdvisor通知它:

<bean id="baseTradeManager" class="org.javatx.spring.aop.TradeDao">

... same as tradeManager definition in the above example

</bean>

<bean id="tradeManager"

class="org.springframework.aop.framework.ProxyFactoryBean">

<property name="proxyInterfaces" value="org.javatx.spring.aop.TradeManager"/>

<property name="target" ref="baseTradeManager"/>

<property name="interceptorNames">

<list>

<idref local="foreignTradeAdvisor"/>

</list>

</property>

</bean>

基本上,就是这样了。我们实现了附加的功能而没有修改原始的组件,而且仅使用Spring应用程序上下文来重新配置依赖性。要想不借助于Spring AOP框架在典型的EJB组件中实现类似的修改,要么必须为EJB添加附加的逻辑(这会使其难以测试),要么必须使用decorator模式(实际上增加了EJB的数量,同时也提高了测试的复杂性,延长了部署时间)。在上面的例子中,您可以看到,借助于Spring,可以轻松地不修改现有组件而向这些组件添加附加的逻辑。现在,您拥有的是几个轻量级组件,而不是紧密耦合的bean,您可以独立测试它们,使用Spring Framework组装它们。注意,使用这种方法,ForeignTradeAdvice就是一个自包含的组件,它实现了自己的功能片断,可以当作一个独立单元在应用服务器外部进行测试,下面我将对此进行说明。

测试通知代码

您可能注意到了,代码不依赖于TradeDao或YahooFeed。这样就可以使用模仿对象完全独立地测试这个组件。模仿对象测试方法允许在组件执行之前声明期望,然后验证这些期望在组件调用期间是否得到满足。要了解有关模仿测试的更多信息,请参见“参考资料”部分。下面我们将会使用jMock框架,该框架提供了一个灵活且功能强大的API来声明期望。

测试和实际的应用程序使用相同的Spring bean配置是个不错的主意,但是对于特定组件的测试来说,不能使用实际的依赖性,因为这会破坏组件的孤立性。然而,Spring允许在创建Spring的应用程序上下文时指定一个BeanPostProcessor,从而置换选中的bean和依赖性。在这个例子中,可以使用模仿对象的一个Map,这些模仿对象是在测试代码中创建的,用于置换Spring配置中的bean:

public class StubPostProcessor implements BeanPostProcessor {

private final Map stubs;

public StubPostProcessor( Map stubs) {

this.stubs = stubs;

}

public Object postProcessBeforeInitialization(Object bean, String beanName) {

if(stubs.containsKey(beanName)) return stubs.get(beanName);

return bean;

}

public Object postProcessAfterInitialization(Object bean, String beanName) {

return bean;

}

}

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/7839366/viewspace-919844/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/7839366/viewspace-919844/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值