java过滤 枪 军火 性,AspectJ: 通往AOSD之路的最佳军火

在AOSD:应用AOP实现业务逻辑中, 我提出关注的接口;

其原文在javaeye上的讨论狼平方也提出可以用event,或者intercepter。

当然不同的方式可以解决不同的问题。这里要讨论一下AspectJ和Event以及intercepter的不同。

1. 先来看看event的方式:需要两个对象Event和EventHandler(EventListener),event和eventHandler,属于数据契约。换句话说,牺牲了编译检查的好处,当然可以应对变化时有一定的好处。一旦需求变化,代码上的变动需要的工作量不少,更为严重的是,如狼平方所说的侵入性太强。

2  接着看interceptor的AOP,相对于Event方式,虽然都是基于数据契约,都给自己做转型,但是代码量少了(因为代码生成),重要的是没有event那样的侵入性。

3. 狼平方做了改进,利用AOP来做brocastEvent的工作。需要做的工作还是很多,甚至我以为这个工作还不如直接用Interceptor来得直接。

如我在小议领域模型(Domain Model) 所说的Domain Service处理两个逻辑:业务规则和流程逻辑,而AOSD:应用AOP实现业务逻辑要试图解决的问题是流程上逻辑,而以上无论是那种方式,都无法解决一个问题:流程信息。

假定现有两个流程如下:

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif

public

class

DomainService

9b8a8a44dd1c74ae49c20a7cd451974e.png

{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif

public

void

bizProcessA()

9b8a8a44dd1c74ae49c20a7cd451974e.png

{

d18c02628675d0a2c816449d98bda930.png        

9b8a8a44dd1c74ae49c20a7cd451974e.png

d18c02628675d0a2c816449d98bda930.png        SomeObject instance

=

doSomeAction(

9b8a8a44dd1c74ae49c20a7cd451974e.png);

d18c02628675d0a2c816449d98bda930.png        

9b8a8a44dd1c74ae49c20a7cd451974e.png

ecedf933ec37d714bd4c2545da43add2.png    }

d18c02628675d0a2c816449d98bda930.png

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif

public

void

bizProcessB()

9b8a8a44dd1c74ae49c20a7cd451974e.png

{

d18c02628675d0a2c816449d98bda930.png        

9b8a8a44dd1c74ae49c20a7cd451974e.png

d18c02628675d0a2c816449d98bda930.png        SomeObject instance

=

doSomeAction(

9b8a8a44dd1c74ae49c20a7cd451974e.png);

d18c02628675d0a2c816449d98bda930.png        

9b8a8a44dd1c74ae49c20a7cd451974e.png

ecedf933ec37d714bd4c2545da43add2.png    }

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif

public

SomeObject doSomeAction(

9b8a8a44dd1c74ae49c20a7cd451974e.png)

9b8a8a44dd1c74ae49c20a7cd451974e.png

{

d18c02628675d0a2c816449d98bda930.png        

9b8a8a44dd1c74ae49c20a7cd451974e.png

ecedf933ec37d714bd4c2545da43add2.png    }

8f1ba5b45633e9678d1db480c16cae3f.png}

这里我们关注的目标方法是doSomeAction(),在doSomeAction中我们希望做些额外的工作,

以狼平方的例子,比如:financialService.createRequestOfMoney(...);

那么无论是用event:

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif

public

SomeObject doSomeAction(

9b8a8a44dd1c74ae49c20a7cd451974e.png)

9b8a8a44dd1c74ae49c20a7cd451974e.png

{

d18c02628675d0a2c816449d98bda930.png 

9b8a8a44dd1c74ae49c20a7cd451974e.png

d18c02628675d0a2c816449d98bda930.png brocastEvent(

new

Event(

9b8a8a44dd1c74ae49c20a7cd451974e.png));

8f1ba5b45633e9678d1db480c16cae3f.png}

还是interceptor:

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif

public

class

SomeInterceptor

implements

MethodInterceptor

9b8a8a44dd1c74ae49c20a7cd451974e.png

{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif

public

Object invoke(MethodInvocation invoke)

9b8a8a44dd1c74ae49c20a7cd451974e.png

{

d18c02628675d0a2c816449d98bda930.png          obj

=

invoke.proceed();

//

执行被拦截的方法完成业务操作

d18c02628675d0a2c816449d98bda930.png

9b8a8a44dd1c74ae49c20a7cd451974e.png.

d18c02628675d0a2c816449d98bda930.png         financialService.createRequestOfMoney(

9b8a8a44dd1c74ae49c20a7cd451974e.png.);

ecedf933ec37d714bd4c2545da43add2.png    }

8f1ba5b45633e9678d1db480c16cae3f.png}

我们注意到,这样做的结果是在bizProcessA()和bizProcessB()的不同业务流程都将导致执行

financialService.createRequestOfMoney

不过我们的流程逻辑要求是:

在bizProcessA()的流程下,执行financialService.createRequestOfMoney

而在bizProcessB的流程下,不执行financialService.createRequestOfMoney。

很明显无论是之上event,还是interceptor的AOP都无法解决这个问题。

面对这样的需求,就需要改进或者重构:

1. 最简单也最直接改doSomeAction(...)为doSomeAction(...boolean flag)。很明显这样的做法很不理想

2. 来点OO的, 将doSomeAction(...)分出去,作为一个接口,采用多态解决。不过依然需要解决动态加载问题,处理起来又需要费点手段。

真的只有这两个手段了吗?不!还有,那就是AspectJ

AspectJ提供了如下

within

withincode

withincode

cflow

cflowbelow

几个内置的pointcut,将可以做到我们要的效果,代码如下:

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif

public

aspect ServiceAspect

9b8a8a44dd1c74ae49c20a7cd451974e.png

{

d18c02628675d0a2c816449d98bda930.png pointcut bp(): cflow(call(

void

DomainService.bizProcessA(..)));

d18c02628675d0a2c816449d98bda930.png pointcut action(): call(doSomeAction(

9b8a8a44dd1c74ae49c20a7cd451974e.png));

d18c02628675d0a2c816449d98bda930.png

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif SomeObject around(

9b8a8a44dd1c74ae49c20a7cd451974e.png) : bp()

&&

action()

&&

args(

9b8a8a44dd1c74ae49c20a7cd451974e.png)

9b8a8a44dd1c74ae49c20a7cd451974e.png

{

d18c02628675d0a2c816449d98bda930.png  SomeObject instance

=

proceed(

9b8a8a44dd1c74ae49c20a7cd451974e.png);

d18c02628675d0a2c816449d98bda930.png  financialService.createRequestOfMoney(

9b8a8a44dd1c74ae49c20a7cd451974e.png.);

d18c02628675d0a2c816449d98bda930.png

return

instance;

ecedf933ec37d714bd4c2545da43add2.png }

8f1ba5b45633e9678d1db480c16cae3f.png}

很显然,AspectJ提供了AOSD所需要的军火。

BTW:本文不针对狼平方同学,只是借由其两篇blog讨论开来,解释了AspectJ优点,以及为什么AspectJ是实现AOSD的最佳也是唯一军火。

事实上很多时候,解决问题的方法有很多,本文旨在阐明AOSD为我们提供了另一条思路。欢迎讨论和拍砖!

另补上我在javaeye讨论贴的完整例子代码,下载。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值