1.背景
首先聊一下,AOP各种通知执行顺序。
aop里面的四种通知类型
- 前置通知
- 后置通知
- 返回通知
- 异常通知
执行顺序
try {
// 执行前置通知
// 执行目标方法
// 执行返回通知
}
catch (Exception e) {
// 执行异常通知
}
finally {
// 执行后置通知
}
我们知道,AOP的底层原理其实是通过动态代理技术,拦截需要代理方法执行的。那么比较容易实现的方式就是将各种通知串成一条链条,将目标方法 + 各种通知串起来执行。
2. CODING
通知方法顶层设计
/**
* 各种通知拦截器
*/
public interface MethodInterceptor {
Object invoke(MethodInterceptorChain methodInterceptorChain);
void doInterceptor();
}
拦截器链
串联目标方法 + 各种通知方法,也可以说是责任链执行的上下文
/**
* 组织 目标方法 + 各种通知方法
*/
@Data
public class MethodInterceptorChain {
/**
* 各种通知方法
*/
final List<MethodInterceptor> methodInterceptors;
/**
* 目前处理到的通知方法 index
*/
int currentIndex;
/**
* 目标对象
*/
Object target;
/**
* 目标方法
*/
Method targetMethod;
/**
* 目标方法执行参数
*/
Object[] methodArgs;
private MethodInterceptorChain() {
currentIndex = -1;
methodInterceptors = new ArrayList<>();
}
public Object process() {
// 所有的通知方法已经执行完成 该执行
if (currentIndex == methodInterceptors.size() - 1) {
// 执行目标方法
try {
return targetMethod.invoke(target, methodArgs);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
return methodInterceptors.get(++currentIndex).invoke(this);
}
public static MethodInterceptorChain from(
Object target,
Method targetMethod,
Object[] methodArgs,
MethodInterceptor... interceptors
) {
unValidParam(target == null, "目标对象不能为null");
unValidParam(targetMethod == null, "目标方法不能为null");
MethodInterceptorChain chain = new MethodInterceptorChain();
chain.setTarget(target);
targetMethod.setAccessible(true);
chain.setTargetMethod(targetMethod);
chain.setMethodArgs(methodArgs);
ofNullable(interceptors).ifPresent(is -> {
for (MethodInterceptor interceptor : is) {
chain.getMethodInterceptors().add(interceptor);
}
});
return chain;
}
}
前置通知 + 后置通知 + 返回通知 + 异常通知
public class BeforeMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInterceptorChain methodInterceptorChain) {
doInterceptor();
return methodInterceptorChain.process();
}
@Override
public void doInterceptor() {
// 前置通知
System.out.println("前置通知");
}
}
public class AfterMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInterceptorChain methodInterceptorChain) {
try {
return methodInterceptorChain.process();
} finally {
doInterceptor();
}
}
@Override
public void doInterceptor() {
System.out.println("执行后置通知");
}
}
public class AfterReturnMethodInterceptor implements MethodInterceptor{
Object rVal;
@Override
public Object invoke(MethodInterceptorChain methodInterceptorChain) {
rVal = methodInterceptorChain.process();
doInterceptor();
return rVal;
}
@Override
public void doInterceptor() {
System.out.println("执行返回通知");
}
}
public class AfterThrowingMethodInterceptor implements MethodInterceptor {
Exception e;
@Override
public Object invoke(MethodInterceptorChain methodInterceptorChain) {
try {
return methodInterceptorChain.process();
} catch (Exception e) {
this.e = e;
doInterceptor();
throw e;
}
}
@Override
public void doInterceptor() {
System.out.println("执行异常通知, " + e.getClass());
}
}
我们可以看到的是不同类型的通知,他们的invoke逻辑不太一样,这里也是说明了为什么后置通知一定会执行,返回通知在出现异常的情况下不会执行,异常通知只有出现异常的时候才会执行,需要去体会一下这个代码设计。
测试类
public class TestService {
public String test() {
throw new IllegalArgumentException("11");
}
}
public static void main(String[] args) throws NoSuchMethodException {
TestService testService = new TestService();
Method method = testService.getClass().getDeclaredMethod("test");
MethodInterceptor beforeMethodInterceptor = new BeforeMethodInterceptor();
MethodInterceptor afterReturnMethodInterceptor = new AfterReturnMethodInterceptor();
MethodInterceptor afterMethodInterceptor = new AfterMethodInterceptor();
MethodInterceptor afterThrowingMethodInterceptor = new AfterThrowingMethodInterceptor();
MethodInterceptorChain chain = MethodInterceptorChain.from(
testService,
method,
null,
beforeMethodInterceptor,
afterMethodInterceptor,
afterReturnMethodInterceptor,
afterThrowingMethodInterceptor
);
System.out.println(chain.process());
}
正常执行
前置通知
执行返回通知
执行后置通知
hello world
出现异常
前置通知
执行异常通知, class java.lang.RuntimeException
执行后置通知
Exception in thread "main" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at com.hdu.chain.MethodInterceptorChain.process(MethodInterceptorChain.java:57)
at com.hdu.interceptor.AfterThrowingMethodInterceptor.invoke(AfterThrowingMethodInterceptor.java:12)
at com.hdu.chain.MethodInterceptorChain.process(MethodInterceptorChain.java:61)
at com.hdu.interceptor.AfterReturnMethodInterceptor.invoke(AfterReturnMethodInterceptor.java:12)
at com.hdu.chain.MethodInterceptorChain.process(MethodInterceptorChain.java:61)
at com.hdu.interceptor.AfterMethodInterceptor.invoke(AfterMethodInterceptor.java:11)
at com.hdu.chain.MethodInterceptorChain.process(MethodInterceptorChain.java:61)
at com.hdu.interceptor.BeforeMethodInterceptor.invoke(BeforeMethodInterceptor.java:10)
at com.hdu.chain.MethodInterceptorChain.process(MethodInterceptorChain.java:61)
at com.hdu.TestMain.main(TestMain.java:28)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.hdu.chain.MethodInterceptorChain.process(MethodInterceptorChain.java:55)
... 9 more
Caused by: java.lang.IllegalArgumentException: 11
at com.hdu.service.TestService.test(TestService.java:7)
... 14 more
3. 总结
上面聊了一下 AOP 的责任链是怎么设计的。
下面说一下AOP的原理大概就是
准备阶段:
- 扫描所有切面类。
- 将切面类的方法提取,构成通知方法。
BeanPostProcessor阶段:
- 根据已有的切面类,使用切点进行匹配
- 如果匹配上了,那么寻找该对象能够匹配上的通知方法
- 为该对象生成一个代理类,代理类的方法拦截里面含有各种通知方法构成的责任链