一.统一转换环绕通知
所有的@Before,@After,@AfterThrowing,等这些通知,最终都会被转换为环绕通知,这是为什么呢?
我们看下面这张图:
当有多个通知时,它会从外层逐渐向内层调用,由外到内,在由内到外,所有最适合的就是环绕通知
比如我们的AspecJMethodtBeforeAdvice最终会被转换为BeforeMethodIntercepter,那么他是如何转换的呢?这就使用了适配器
二.适配器模式
当有两个类型要相互转换的时候,可以借助适配器来实现
MethodBeforeAdviceAdapter就是将前置通知切面转换为环绕通知,
三.模拟实现调用链
这些环绕通知可以使用递归的方式来依次调用,下面我们来模拟实现调用链
1.创建目标类
/**
* 要增强的目标类
*/
class Target{
public void foo(){
System.out.println("foo...");
}
}
2.创建两个自定义通知
/**
* 自定义通知1
*/
class MyMethodInterceptor1 implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("advice1 before...");
Object result = invocation.proceed();
System.out.println("advice1 after...");
return result;
}
}
/**
* 自定义通知2
*/
class MyMethodInterceptor2 implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("advice2 before...");
Object result = invocation.proceed();
System.out.println("advice2 after...");
return result;
}
}
3.创建调用链
/**
* 自定义调用链
*/
class MyMethodInvocation implements MethodInvocation{
//四个属性
//目标类需要增强的方法
private Method method;
//目标对象
private Object target;
//增强方法所需要的参数数组
private Object[] args;
//通知集合
private List<MethodInterceptor> methodInterceptorList;
//用一个计数器来判断递归结束
private int count = 1;
public MyMethodInvocation(Method method, Object target, Object[] args, List<MethodInterceptor> methodInterceptorList) {
this.method = method;
this.target = target;
this.args = args;
this.methodInterceptorList = methodInterceptorList;
}
//返回需要增强的方法对象
@Override
public Method getMethod() {
return method;
}
//返回方法参数
@Override
public Object[] getArguments() {
return args;
}
/**
* 主要的方法是这个:
* 它通过递归调用实现通知的方法
* @return
* @throws Throwable
*/
@Override
public Object proceed() throws Throwable {
/**
* 分析一下,假如通知集合中有两个通知,那么我们需要
* 调用三次,调用第一次通知,第二次通知,第三次是目标对象的方法
* 所有我们可以让count < 集合大小的时候继续调用
* 当count > 集合大小的时候,通知就调用完了
* 该调用目标方法了
*/
if(count > methodInterceptorList.size()){
return method.invoke(target);
}
//继续递归调用
MethodInterceptor advice = methodInterceptorList.get(count - 1);
//对count加一
count++;
return advice.invoke(this);
}
//返回需要增强的目标对象
@Override
public Object getThis() {
return target;
}
@Override
public AccessibleObject getStaticPart() {
return method;
}
}
4.测试调用链
public class testMyInvocation {
public static void main(String[] args) throws Throwable {
Target target = new Target();
List<MethodInterceptor> interceptorList =new ArrayList<>();
interceptorList.add(new MyMethodInterceptor1());
interceptorList.add(new MyMethodInterceptor2());
//创建调用链对象
MyMethodInvocation invocation =
new MyMethodInvocation(target.getClass().getMethod("foo"),
target,new Object[0],interceptorList);
//调用方法
invocation.proceed();
}
}
5.运行查看结果
advice1 before...
advice2 before...
foo...
advice2 after...
advice1 after...
可以看到已经成功实现了环绕通知的递归调用!