使用cglib实现简单的aop模块
around还有些问题。
需要jar包cglib-nodep-2.1_3
,或者 maven 加上
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.4</version>
</dependency>
版本视情况改变。
假设有这么个目标类型
public class TestTarget {
public void out(String a) {
System.out.println("Target out."+a);
}
}
TestTarget类里面有个out
方法,我们希望在out
方法执行的时候打log。
增强器Enhancer可以增强原有的方法,并返回一个新的对象。
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(TestTarget.class);
enhancer.setCallback(callback);
代码创建一个enhancer,然后把一个Class<TestTarget>
对象传进去,enhancer对它干了什么,暂时不用理。
随后传入一个callback,callback是这样的:
public class BeforeCallBack implements MethodInterceptor {
public BeforeCallBack() {
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
// do something here.
return methodProxy.invokeSuper(o, objects);
}
}
BeforeCallBack
实现了MethodInterceptor
接口。这里才是真正的增强,在return原有的方法之前,执行一些东西(这里是before切点,也可以改成after、around)
效果:
此处匿名内部类实现的接口并替换成lambda。
public class MainClass {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(TestTarget.class);
enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
System.out.println("before.");
return methodProxy.invokeSuper(o,objects);
});
TestTarget testTarget = (TestTarget) enhancer.create();
testTarget.out();
}
}
class TestTarget{
public void out(){
System.out.println("out. ");
}
}
before.
out.
在增强的时候,我们并没有指定是哪一个方法被增强,所以类里面的所有方法都会被起作用。
cglib提供了CallbackFilter
来区分什么方法应该使用什么Callback(before、after..etc)来处理。
用来标记方法类型的,注解@interface
无疑是最合适的了。
我们在拦截了方法之后,在它返回前后进行一些操作,在intercept
方法里边写上我们要有的操作。
也就是说,每有一个Callback的需求,我们都要手动的实现接口并且加上业务代码。那么我们应该把业务代码抽取出来。
把业务抽象成一个切面,比如打log,我们有个LogAspect,继承于AbstractAspect,届时,只要在intercept
跑抽象的方法就可以了。
比如:
public class BeforeCallBack implements MethodInterceptor {
Class<? extends AbstractAspect> aspect;
public BeforeCallBack(Class<? extends AbstractAspect> aspect) {
this.aspect = aspect;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
AbstractAspect instance = aspect.newInstance();
instance.doBefore();
return methodProxy.invokeSuper(o, objects);
}
}
不管实际上的切面是什么,他都是AbstractAspect
。
主要的注解有两个:Aspect
、PointCut
,一个是用于标记TargetClass要应用什么切面,一个是用于标记方法的切点类型(before、after..)