Guice AOP生火指南

转载自:http://www.breakthen.com/2011/09/14/guice-aop-kick-start/

听说Guice的时候很早,但了解的不多,写过一些简单的例子,无非都是依赖注入(Dependency Injection)方面的,今天跟朋友聊起来Guice,就去看了看google code上的文档,发现Guice竟然也支持AOP,真是孤陋寡闻了。
看了看文档,发现用起来比较简单,下面举个简单的例子来说明。
Guice的AOP是通过借助Annotation实现的,在需要进行拦截的方法上加自定义的注解。

比如下面的一个注解NeedLog,表示在方法调用的时候需要记一下日志,代码如下:

?
1
2
3
4
@Retention (RetentionPolicy.RUNTIME) @Target (ElementType.METHOD)
public @interface NeedLog {
 
}

这个注解是非常简单的,除了指明它作用在方法上,没有做任何事。
接下来定义业务类,BizService。代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class BizService {
 
     @NeedLog
     public void doFoo(){
         System.out.println( "do foo" );
     }
 
     public void doBiz(){
         System.out.println( "do biz" );
     }
 
     @NeedLog
     public void doBar(){
         System.out.println( "do bar" );
     }
 
     @NeedLog
     public void doSomethingWithParams(String param){
         System.out.println( "do something with params: " + param);
     }
}

这个类定义了四个业务方法,其中doFoo, doBar, doSomethingWithParams使用了NeedLog注解,doBiz没有使用,另外,doSomethingWithParams这个方法还带了参数。

接下来需要实现一个MethodInterceptor,方法拦截器。它在被拦截的方法被调用的时候执行,以便有机会来获得被调用方法的上下文,包括方法名称,参数列表,参数值,然后代理给其它类来执行一些交叉的逻辑(cross-cutting logic,如日志、事务处理、验证授权等),最终,它有机会来判断返回值、抛出的异常或是简单的返回。拦截器可能会被应用于大量的方法并被多次调用,因此它们必须是高效的、非侵入的。

下面定义的LogInterceptor,简单的打印了一下被拦截的方法名,如果被拦截的方法有参数,将参数输出出来。代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
public class LogInterceptor implements MethodInterceptor {
     @Override
     public Object invoke(MethodInvocation invocation) throws Throwable {
         System.out.println( "log something when " + invocation.getMethod().getName() + " invoked." );
         Object[] args = invocation.getArguments();
         for (Object arg : args){
             System.out.println( "[Argument:" + arg.toString() + "]" );
         }
         return invocation.proceed();
     }
}

接下来需要做一次绑定:

?
1
2
3
4
5
6
7
8
public class LogModule extends AbstractModule {
     @Override
     protected void configure() {
         bindInterceptor(Matchers.any(), Matchers.annotatedWith(NeedLog. class ),
                 new LogInterceptor());
     }
 
}

bindInterceptor方法有两个Matchers的参数,Matcher是一个简单的接口,用来表示是否匹配;在Guice AOP中,需要两个Matcher:一个表示参与的类,另一个代表相关的方法。除any()外,Matchers还提供了如identicalTo、inPackage、inSubpackage等方法用来匹配,具体用法可参考这里

最后来看一下调用的例子:

?
1
2
3
4
5
6
7
8
9
10
public class Program {
     public static void main(String[] args) {
         Injector injector = Guice.createInjector( new LogModule());
         BizService service = injector.getInstance(BizService. class );
         service.doBiz();
         service.doBar();
         service.doFoo();
         service.doSomethingWithParams( "this is a param" );
     }
}

输出结果为:

?
1
2
3
4
5
6
7
8
do biz
log something when doBar invoked.
do bar
log something when doFoo invoked.
do foo
log something when doSomethingWithParams invoked.
[Argument:this is a param]
do something with params: this is a param

Guice的方法拦截也是通过动态生成字节码来实现的,通过创建子类重写相应的方法来实现拦截,不支持字节码生成的平台如Android就没法用了。

文档中还列出了被拦截的类与方法需要满足的条件:

1.类必须是public的或包内可见的;

2.类必须是非final的;

3.方法必须是public的、包内可见的或是protected的;

4.方法必须是非final的;

5.实例必须通过无参数的构造函数生成或者通过guice的@inject注解构造。

最后一点,guice实现的方法拦截API是AOP  Alliance定义的公共规范的一部分,因此在不同framework之间提供了很好的可移植性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值