Google Guice 是一个轻量级的依赖注入框架,它支持Java 5或者更高版本的JDK,得利于Java 5中提供的泛型 (Generics) 和注解 (Annotations) ,它可以使得代码类型安全…
May 5, 2017
JAVA: Google Guice 学习AOP (面向切面的编程)
Guice的AOP还是很弱的,目前仅仅支持方法级别上的,另外灵活性也不是很高。看如下示例:
Guice支持AOP的条件是:
类必须是public或者package (default) 类不能是final类型的 方法必须是public,package或者protected 方法不能使final类型的 实例必须通过Guice的@Inject注入或者有一个无参数的构造函数
且看示例代码
1、定义接口
package com.guice.AOP; import com.google.inject.ImplementedBy; @ImplementedBy(ServiceImpl.class) public interface Service { public void sayHello(); }
2、定义实现类
package com.guice.AOP; import com.google.inject.Singleton; import com.google.inject.name.Named; @Singleton public class ServiceImpl implements Service { @Named("log") @Override public void sayHello() { System.out.println(String.format("[%s#%d] execute %s at %d", this.getClass().getSimpleName(), hashCode(), "sayHello", System.nanoTime())); } }
3、定义切面
package com.guice.AOP; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; /** * TODO :自定义的方法拦截器,用于输出方法的执行时间 * * @author E468380 */ public class LoggerMethodInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { String name = invocation.getMethod().getName(); long startTime = System.nanoTime(); System.out.println(String.format("before method[%s] at %s", name, startTime)); Object obj = null; try { obj = invocation.proceed();// 执行服务 } finally { long endTime = System.nanoTime(); System.out.println(String.format("after method[%s] at %s, cost(ns):%d", name, endTime, (endTime - startTime))); } return obj; } }
4、测试类
package com.guice.AOP; import com.google.inject.Binder; import com.google.inject.Guice; import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Module; import com.google.inject.matcher.Matchers; import com.google.inject.name.Names; public class AopTest { @Inject private Service service; public static void main(String[] args) { Injector injector = Guice.createInjector(new Module() { @Override public void configure(Binder binder) { binder.bindInterceptor(Matchers.any(), Matchers.annotatedWith(Names.named("log")), new LoggerMethodInterceptor()); } }); injector.getInstance(AopTest.class).service.sayHello(); injector.getInstance(AopTest.class).service.sayHello(); injector.getInstance(AopTest.class).service.sayHello(); } }
输出结果:
before method[sayHello] at 18832801981960 [ServiceImpl$$EnhancerByGuice$$d4244950#1109685565] execute sayHello at 18832817170768 after method[sayHello] at 18832817378285, cost(ns):15396325 before method[sayHello] at 18832817542181 [ServiceImpl$$EnhancerByGuice$$d4244950#1109685565] execute sayHello at 18832817640327 after method[sayHello] at 18832817781772, cost(ns):239591 before method[sayHello] at 18832817920651 [ServiceImpl$$EnhancerByGuice$$d4244950#1109685565] execute sayHello at 18832818013023 after method[sayHello] at 18832818132657, cost(ns):212006
关于此结果有几点说明:
(1)由于使用了AOP我们的服务得到的不再是我们写的服务实现类了,而是一个继承的子类,这个子类应该是在内存中完成的。
(2)除了第一次调用比较耗时外(可能guice内部做了比较多的处理),其它调用事件为0毫秒(我们的服务本身也没做什么事)。
(3)确实完成了我们期待的AOP功能。
5、切面注入依赖
如果一个切面(拦截器)也需要注入一些依赖怎么办?
在这里我们声明一个前置服务,输出所有调用的方法名称。
①定义接口
package com.guice.AOP; import org.aopalliance.intercept.MethodInvocation; import com.google.inject.ImplementedBy; @ImplementedBy(BeforeServiceImpl.class) public interface BeforeService { void before(MethodInvocation invocation); }
②定义实现类
package com.guice.AOP; import org.aopalliance.intercept.MethodInvocation; public class BeforeServiceImpl implements BeforeService { @Override public void before(MethodInvocation invocation) { System.out.println("Before--->" + invocation.getClass().getName()); } }
③定义切面
package com.guice.AOP; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import com.google.inject.Inject; //这个切面依赖前置服务 public class AfterMethodIntercepter implements MethodInterceptor { @Inject private BeforeService beforeService; @Override public Object invoke(MethodInvocation invocation) throws Throwable { beforeService.before(invocation); Object obj = null; try { obj = invocation.proceed(); } finally { System.out.println("after--->" + invocation.getClass().getName()); } return obj; } }
④编写测试类
package com.guice.AOP; import com.google.inject.Binder; import com.google.inject.Guice; import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Module; import com.google.inject.matcher.Matchers; import com.google.inject.name.Names; public class AopTest2 { @Inject private Service service; public static void main(String[] args) { Injector injector = Guice.createInjector(new Module() { @Override public void configure(Binder binder) { AfterMethodIntercepter after = new AfterMethodIntercepter(); binder.requestInjection(after); binder.bindInterceptor(Matchers.any(), Matchers.annotatedWith(Names.named("log")), after); } }); injector.getInstance(AopTest2.class).service.sayHello(); } }
输出结果:
Before--->com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation [ServiceImpl$$EnhancerByGuice$$618294e9#506575947] execute sayHello at 20140444543338 after--->com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation
说明
Binder绑定一个切面的API是:
com.google.inject.Binder.bindInterceptor(Matcher<? super Class<?>>, Matcher<? super Method>, MethodInterceptor...)
第一个参数是匹配类,第二个参数是匹配方法,第三个数组参数是方法拦截器。也就是说目前为止Guice只能拦截到方法,然后才做一些切面工作。
注意
尽管切面允许注入其依赖,但是这里需要注意的是,如果切面依赖仍然走切面的话那么程序就陷入了死循环,很久就会堆溢出。
Guice的AOP还是很弱的,目前仅仅支持方法级别上的,另外灵活性也不是很高。
本文: JAVA: Google Guice 学习AOP (面向切面的编程)