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还是很弱的,目前仅仅支持方法级别上的,另外灵活性也不是很高。