因为项目上需要使用Guice,而Guice并不像Spring那样提供一整套的解决方案(Spring是一个容器,而厌烦了容器的我选择了不属于容器的Guice1.0)。因此,在事务支持方面肯定不是依赖于Guice自己来实现。而我们都知道无论是日志还是事务,使用Aop的方案都是比较好的,而在学习过程中没有发现比较好的材料,于是通过官方的文档,还有Robbie Vanbrabant的书Apress.Google.Guice.Agile.Lightweight Dependency Injection Framework第四章的知识,总结出下面的内容。
其中代码示例来自于Robbie的原著,在这里相当于转载。
将aopalliance.jar放在Classpath下,我是与Guice-1.0.jar放在一起,程序就可以工作并使用AOP了。
1.Guice1.0如何实现Aop
Guice将使用代理的方式包装原来的类(我称之为目标类),为每一个目标类创建一个代理,通过代理实现Aop的功能,而创建的过程只需要通过在Module中绑定就可以完成,因此感觉不出代理类的创建。由于Guice的目标就是帮我们解决类的高效的创建问题,因此,对于代理类的创建应该也是很快的,因为还没有看过Guice的源代码,暂时不清楚其“快”是如何实现的。
2.Guice1.0的Aop的作用范围
因为还没有完全使用过Guice的所有功能,目前,我所知道的是Guice1.0仅支持对方法进行Aop操作。而Bob Lee自己也是Aop方面的专家,因此我感觉Guice的后续版本应该会支持更多更灵活的Aop操作。
3.Guice1.0是否可用
我看过Guice2.0的规划,与Guice1.0有98%的兼容,并且功能比Guice1.0更加全面,包括Aop的支持,而现在Guice1.0的功能已经足够充当一个完整的IoC框架了,因此现在Guice1.0已经进入了可用的状态。
4.Guice1.0在Module中对Aop的配置
void bindInterceptor(Matcher<? super Class<?>> classMatcher, Matcher<? super Method> methodMatcher, MethodInterceptor... interceptors) {...}
这就是Guice中Binder类中用于进行Aop操作的类,通过配置”目标类“和”目标方法”,就可以配置一个或多个方法对“目标方法”进行拦截。
5.Guice1.0的Aop允许实现的操作
6.MethodInvocation.proceed()直接跨越Aop拦截器
通过调用这个方法,可以直接获取“目标方法”真正的返回值而不被Aop的拦载方法干扰
好的,了解了这些知识以后,我们开始用一个例子讲解如何使用Guice1.0的Aop。例子程序使用Robbie的代码,在这里将顺序改变一下以适应于学习(以我个人的观点)
首先,我们先考虑一个问题,我们假定有一个类被创建后,应该有一个类去接收这个类执行的结果,但我们需要做另外两个类来拦截这个方法,其中一个类用于记录这个类要执行什么操作,第二个类将接收者替换成其他的对象。
现实的一个例子,你要打电话给Aunt Jane,但是FBI将会偷偷从中间截获你的电话,然后记录下你要播打的电话号码,然后还会将你的电话转给FBI的另一个人,让你以为已经接通了电话(但实际上你并不知道是否由Aunt Jane接收,因为电话已经被Aop过了,就是已经被拦截,记录了你播的号码并转给了另一个FBI特工)。
1.首先,创建“你”,就是电话的发出者,同时,也要创建电话的接收者对象。
下面就是电话的播出者,通过HashMap作为电话本(可以理解为电话接线员)
import java.util.HashMap; import java.util.Map; public class Phone { private static final Map<Number, Receiver> RECEIVERS = new HashMap<Number, Receiver>(); static { RECEIVERS.put(123456789, new Receiver("Aunt Jane")); RECEIVERS.put(111111111, new Receiver("Santa")); } public Receiver call(Number number) { return RECEIVERS.get(number); } }
下面就是电话接收者对象:
public class Receiver { private final String name; public Receiver(String name) { this.name = name; } @Override public String toString() { return String.format("%s[name=%s]", getClass().getName(), name); } }
2.开始转入“FBI”式操作,创建两个操作,这两个操作将被配置在Phone对象的call方法执行时,拦截这个操作,记录电话号码并将电话转给另一个人。这两个操作都要实现Guice的MethodInterceptor接口,因为这样Guice才能在注入的时候进行拦截。
先是配置记录电话号码的类:
import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; public class PhoneLoggerInterceptor implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable { for (Object arg : invocation.getArguments()) if (arg instanceof Number) System.out.println("CALL: "+arg); return invocation.proceed(); } }
然后是执行转接电话操作的类:
import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; public class PhoneRedirectInterceptor implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable { return new Receiver("Alberto's Pizza Place"); } }
3.下面是发起操作(进行打电话)
import com.google.inject.Guice; import com.google.inject.Injector; public class MakePhoneCall { public static void main(String[] args) { Injector i = Guice.createInjector(new PhoneModule()); Phone phone = i.getInstance(Phone.class); Receiver auntJane = phone.call(123456789); System.out.println(auntJane); } }
4.但按照上面的做法并不会进行Aop操作,因为还没有按照Guice的“哲学”去进行Module的配置。下面是进行Guice的Module的配置:
import static com.google.inject.matcher.Matchers.only; import static com.google.inject.matcher.Matchers.returns; import static com.google.inject.matcher.Matchers.subclassesOf; import com.google.inject.AbstractModule; public class PhoneModule extends AbstractModule { protected void configure() { bindInterceptor( subclassesOf(Phone.class), returns(only(Receiver.class)), new PhoneLoggerInterceptor(), new PhoneRedirectInterceptor() ); } }
5.这时,在重新发起打电话的操作(执行第三步创建的类),就可以从console中看到输出的结果了。
以上就是Guice的一个Aop的例子,在使用的时候还是比较方便简单的,并且速度上也很快,也很容易理解。而Guice的Aop可以对拦截设定范围,具体的范围可以看一下Api文档,比较简洁的几个操作(但基本上都够用了)。
有了这种Aop的操作,就可以在一定程度上对系统的日志(非Log4J这种日志),还有事务,权限等操作进行 Aop编程了。
再次感谢Robbie和Robbie所做的工作。
Thanks for Bob lee's Guice and Robbie's good book: Apress.Google.Guice.Agile.Lightweight Dependency Injection Framework. All code quoted from this book. Thank you, Robbie Vanbrabant.