使用cglib实现简单的aop模块 **around还有些问题。** #### jar包 需要jar包`cglib-nodep-2.1_3`,或者 maven 加上 ``` xml cglib cglib 3.2.4 ``` 版本视情况改变。 #### 目标类 假设有这么个目标类型 ``` java public class TestTarget { public void out(String a) { System.out.println("Target out."+a); } } ``` TestTarget类里面有个`out`方法,我们希望在`out`方法执行的时候打log。 #### 增强器 增强器Enhancer可以增强原有的方法,并返回一个新的对象。 ``` java Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(TestTarget.class); enhancer.setCallback(callback); ``` 代码创建一个enhancer,然后把一个`Class` 对象传进去,enhancer对它干了什么,暂时不用理。 随后传入一个callback,callback是这样的: ``` java 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。 ``` java 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. "); } } ``` --- ``` bash before. out. ``` #### 通用化 * 切点 在增强的时候,我们并没有指定是哪一个方法被增强,所以类里面的所有方法都会被起作用。 cglib提供了`CallbackFilter`来区分什么方法应该使用什么Callback(before、after..etc)来处理。 用来标记方法类型的,注解`@interface`无疑是最合适的了。 * 切面 我们在拦截了方法之后,在它返回前后进行一些操作,在`intercept`方法里边写上我们要有的操作。 也就是说,每有一个Callback的需求,我们都要手动的实现接口并且加上业务代码。那么我们应该把业务代码抽取出来。 **把业务抽象成一个切面**,比如打log,我们有个LogAspect,继承于AbstractAspect,届时,只要在`intercept`跑抽象的方法就可以了。 比如: ``` java public class BeforeCallBack implements MethodInterceptor { Class aspect; public BeforeCallBack(Class 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..) #### demo [gitee demo](https://gitee.com/someonedeng/DAop.git)