本站首页    管理页面    写新日志    退出


«August 2025»
12
3456789
10111213141516
17181920212223
24252627282930
31


公告
 本博客在此声明所有文章均为转摘,只做资料收集使用。

我的分类(专题)

日志更新

最新评论

留言板

链接

Blog信息
blog名称:
日志总数:1304
评论数量:2242
留言数量:5
访问次数:7575990
建立时间:2006年5月29日




[Spring]AOSD:应用AOP实现业务逻辑
软件技术,  电脑与网络

lhwork 发表于 2006/7/8 18:23:39

(下面是发在javaeye上的帖子,因为觉的还有点意思,转到blog来,关于Domain和AOSD已经有了一些新的想法)应用Domain开发的系统,通常把逻辑放在Domain Service层中,而Domain Service做两个工作:1. 和表现层通信,表现为把表现层的平面数据(VO)转换为相关联的Domain对象,把Domain对象计算的结果转换成平面数据(VO)返回给表现层;2.根据Use Case完成商业逻辑的调度。以下主要讨论Use Case的内容。 通常Use Case所描述的Business Flow分为四种:Basic Flow,Alternate Flow,Exception Flow和Extension Flow。 虽 然Business Flow可能包含很多领域对象,由于每个use case的目标带有浓厚的领域逻辑,因而可以通过分析提炼出一个主domain对象。然后重组转换来自BA或者PM的BP设计文档,使其中的Basic Flow基于主domain对象,而把 Alternate Flow,Exception Flow和 Extension Flow基于其它的Domain Service和Domain Object(当然包括Util objects), 最后利用AOP把Alternate Flow, Exception Flow和Extension Flow 与Basic Flow在Service层组织起来。 使用AOP来组织Use Case时,与使用AOP组织技术问题(比如日志,权限检查和事务处理等)不同。 在AOP组织技术问题时,我们不关心join point的目标对象和目标方法以及入口参数。比如:  500)this.width=500'>500)this.width=500'>public class BankServiceImpl implements BankService500)this.width=500'>{ 500)this.width=500'>public void transfer(UserAccount src, UserAccount dist, 500)this.width=500'>500)this.width=500'>BigDecimal amount)throws Exception500)this.width=500'>{ 500)this.width=500'>        src.subtract(amount); 500)this.width=500'>        dist.add(amount); 500)this.width=500'>} 500)this.width=500'>//Other code goes here500)this.width=500'> 500)this.width=500'>} 500)this.width=500'> 500)this.width=500'> < bean id = "  BankService "   class = " org.  500)this.width=500'> springframework.transaction.interceptor.TransactionProxyFactoryBean " >  500)this.width=500'>      < property name = " transactionAttributes " >  500)this.width=500'>          < props >  500)this.width=500'> < prop key = " transfer " > PROPAGATION_REQUIRED </ prop >                   500)this.width=500'>          </ props >  500)this.width=500'>     </ property >  500)this.width=500'> </ bean >  500)this.width=500'> 我们不关心参数,或者在一些方法重载的地方利用参数来识别区分我们的方法入口。 但当我们利用AOP来组织Use Case时我们关心目标对象和目标方法以及入口参数。因为AOP所要织入的方法是另一个Use Case是另一个Biz Flow。(这个在AOSD中显示讨论的不多,只有在12章12.4.中有提到) 比如我们要在转帐成功后发手机短信通知客户。那么在没有用AOP代码中我们这样写: 500)this.width=500'>500)this.width=500'>public class BankServiceImpl implements BankService500)this.width=500'>{ 500)this.width=500'>public void transfer(UserAccount src, UserAccount dist, 500)this.width=500'>500)this.width=500'>BigDecimal change)throws Exception500)this.width=500'>{ 500)this.width=500'>        src.subtract(change); 500)this.width=500'>        dist.add(change); 500)this.width=500'>        SMSService.sendSMS(src, change); 500)this.width=500'>        SMSService.sendSMS(dist, change); 500)this.width=500'>} 500)this.width=500'>//Other code goes here500)this.width=500'> 500)this.width=500'>} 500)this.width=500'>500)this.width=500'>Public class SMSService 500)this.width=500'>{ 500)this.width=500'>500)this.width=500'>        public static void sendSMS(UserAccount user, BigDecimal change)500)this.width=500'>{ 500)this.width=500'>             Long phone = user.getPhoneNumber(); 500)this.width=500'>             BigDecimal balance = user.getBalance(); 500)this.width=500'>             send(phone, change, belance) 500)this.width=500'>} 500)this.width=500'>500)this.width=500'>private static void send(Long phone, change, balance)500)this.width=500'>{ 500)this.width=500'>500)this.width=500'> 500)this.width=500'>} 500)this.width=500'>} 500)this.width=500'> 事实用User Case的观点分析,发送短信通知是另一个use case,是转帐这个use case的extend flow。用AOP的方法应该如下: 500)this.width=500'>500)this.width=500'>public class BankServiceEx 500)this.width=500'>{ 500)this.width=500'>500)this.width=500'>public static void notify(UserAccount src, BigDecimal change) 500)this.width=500'>{ 500)this.width=500'>        SMSService.sendSMS(src, change); 500)this.width=500'>} 500)this.width=500'>//Other code goes here500)this.width=500'> 500)this.width=500'>} 500)this.width=500'>500)this.width=500'>500)this.width=500'>public aspect BankServiceAspect 500)this.width=500'>{ 500)this.width=500'>pointcut transfer():call(void BankService.transfer(..)); 500)this.width=500'>        500)this.width=500'>500)this.width=500'>        after(UserAccount src, UserAccount dist, BigDecimal change) returning : transfer() && args(src, dist, change)500)this.width=500'>{ 500)this.width=500'>        BankServiceEx.notify(src, change); 500)this.width=500'>BankServiceEx.notify(dist, change); 500)this.width=500'>        } 500)this.width=500'>} 500)this.width=500'>500)this.width=500'> 这样我们完成了两个用例的分离,两个用例独立,可以重用和测试。比如上述短信通知用例其实可以被重用到其它情况如:存款,消费,以及银行分红等等。 不 过可能面临一个情况是,两个独立用例的代码部分都可能用到某个对象, 那么在两个用例中可能重复一部分代码。虽然从概念上看,不应该重复(在使用用旧的方法实现时不会重复),但从不同use case看,这个重复是值得的。曾经考虑利用代码生成,直接获得Local Variable,这样可以减少重复,但是这个想法是错误的,不仅仅是实现上的困难,更重要在于,分离出的发送短信用例便绑定了转帐用例,依赖于转帐用 例,而无法独立重用和测试。 这样,对象、方法以及方法参数构成了一个完整的pointcut,成为不同用例切片的共同入口,相当于一个占位符。这个时候就需要不同的用例实现人员协调好该入口。


阅读全文(1881) | 回复(-1) | 编辑 | 精华
 



发表评论:
昵称:
密码:
主页:
标题:
验证码:  (不区分大小写,请仔细填写,输错需重写评论内容!)



站点首页 | 联系我们 | 博客注册 | 博客登陆

Sponsored By W3CHINA
W3CHINA Blog 0.8 Processed in 0.062 second(s), page refreshed 144759750 times.
《全国人大常委会关于维护互联网安全的决定》  《计算机信息网络国际联网安全保护管理办法》
苏ICP备05006046号