024:SpringBean的Aop通知调用链源码分析
1 SpringAop底层调用链源码分析演示
课程内容:
1.SpringAop源码分析之通知调用链关系
2.递归算法与循环算法区别
3.基于递归算法+责任链模式实现SpringAop调用链
2 SpringAop底层源码流程回顾
SpringAop的底层实现原理
设计模式的运用:代理设计模式、底层五个通知形成调用链采用责任链模式
SpringAop源码分析
- 配置@EnableAspectJAutoProxy注解开启SpringAop;
- @Import(AspectJAutoProxyRegistrar.class)往IOC容器中注入SpringAop切面类;
- registerAspectJAnnotationAutoProxyCreatorIfNecessary()注册切面类;
- AnnotationAwareAspectJAutoProxyCreator.class注册到IOC容器中,AOP入口;
SpringBean的生命周期中,后置处理器在bean对象初始化之前和之后实现处理。根据源码分析可知,AbstractAutoProxyCreator 祖宗类有BeanPostProcessor。 - beanProcessor.postProcessAfterInitialization(result, beanName);
- wrapIfNecessary()判断该对象是否在aop切入点扫包范围内;
- createAopProxy()判断该被代理类是否有实现接口,如果有实现接口的话,采用jdk动态代理,否则使用cglib代理;
- 使用JDKDynamicAopProxy创建代理类对象;
- 当在调用目标方法的时候就会执行到JDKDynamicAopProxy的invoke方法;
- 底层使用集合存放五种通知,然后再使用责任链模式循环的调用。
3 循环遍历与递归算法实现的区别
可以使用递归算法代替循环使用
public class Test {
private static int index; // 记录当前循环调用的位置
public static void main(String[] args) {
// 循环目的 遍历数据
ArrayList<String> strings = new ArrayList<>();
strings.add("mayikt");
strings.add("maple");
strings.add("fire");
// for (int i = 0; i < strings.size(); i++) {
// System.out.println(strings.get(i));
// }
// 递归算法 循环不停调用自己的方法 自己调用自己 有栈的深度
recurrence(strings);
}
// 自己调用自己 代替循环 场景:查询数据量过大内存溢出
public static void recurrence(ArrayList<String> strings) {
if(index == strings.size()){
// 数据已经获取完毕,退出防止溢出
return;
}
String s = strings.get(index++);
System.out.println("s:" + s);
recurrence(strings);
}
}
4 纯手写SpringAop调用链思路分析
Aop调用链依赖关系:前置通知→环绕通知之前→目标方法→环绕通知之后→后置通知
底层通过递归算法+责任链模式实现
SpringAop使用集合存放五个通知链 有序
[0] 环绕通知之前
[1] 前置通知
[2] 环绕通知之后
[3] 后置通知
执行目标方法→通过递归算法指针指定目标方法的执行
5 纯手写SpringAop调用链代码01
6 纯手写SpringAop调用链代码02
模拟SpringAop五个通知调用链关系
目标方法
public class UserService {
public void login(String userName, Integer userAge) {
System.out.println("userName:" + userName + ",userAge:" + userAge);
}
}
方法拦截器接口及前置/后置通知实现类
public interface MethodInterceptor {
/**
* 定义共同通知骨架
*/
public void invoke(MethodInvocation methodInvocation) throws InvocationTargetException, IllegalAccessException;
}
public class BeforeMethodInterceptor implements MethodInterceptor {
@Override
public void invoke(MethodInvocation methodInvocation) throws InvocationTargetException, IllegalAccessException {
System.out.println(">>前置通知");
methodInvocation.process();// 递归调用
}
}
public class AfterMethodInterceptor implements MethodInterceptor {
@Override
public void invoke(MethodInvocation methodInvocation) throws InvocationTargetException, IllegalAccessException {
methodInvocation.process();
System.out.println(">>后置通知");
}
}
方法执行接口及实现类
public interface MethodInvocation {
public void process() throws InvocationTargetException, IllegalAccessException;
}
public class DefaultMethodInvocation implements MethodInvocation {
public DefaultMethodInvocation(List<MethodInterceptor> methodInterceptors) {
this.methodInterceptors = methodInterceptors;
}
public DefaultMethodInvocation(List<MethodInterceptor> methodInterceptors, Object target, Method method, Object[] args) {
this.methodInterceptors = methodInterceptors;
this.target = target;
this.method = method;
this.args = args;
}
// 存放所有的通知
private List<MethodInterceptor> methodInterceptors;
private Object target;// 目标对象
private Method method;// 目标方法
private Object args[];// 目标参数
private int index; // 记录当前链调用位置
/**
* 能够把通知链形成关联
*
* @return
*/
@Override
public void process() throws InvocationTargetException, IllegalAccessException {
if (index == methodInterceptors.size()) {
method.invoke(target, args);// 通过java反射机制执行目标方法
return;
}
MethodInterceptor methodInterceptor = methodInterceptors.get(index++);
methodInterceptor.invoke(this);
}
}
测试类
public class Test001 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// 1.装配所有的通知存放到集合中
ArrayList<MethodInterceptor> methodInterceptors = new ArrayList<>();
methodInterceptors.add(new BeforeMethodInterceptor());
methodInterceptors.add(new AfterMethodInterceptor());
// 2.创建目标方法
UserService userService = new UserService();
Method loginMethod = UserService.class.getMethod("login", String.class, Integer.class);
Object[] objects = {"mayikt", 666};
new DefaultMethodInvocation(methodInterceptors, userService, loginMethod, objects).process();
}
}
运行结果:
要点:当执行到后置通知的时候,先回调,回调函数中此时刚好满足指针记录等于列表长度条件,执行目标方法,返回继续执行后置通知。
7 纯手写SpringAop调用链代码03
加上环绕通知
public class AroundMethodInterceptor implements MethodInterceptor {
@Override
public void invoke(MethodInvocation methodInvocation) throws InvocationTargetException, IllegalAccessException {
System.out.println(">>环绕通知之前");
methodInvocation.process();
System.out.println(">>环绕通知之后");
}
}
public class Test001 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// 1.装配所有的通知存放到集合中
ArrayList<MethodInterceptor> methodInterceptors = new ArrayList<>();
methodInterceptors.add(new AroundMethodInterceptor());
methodInterceptors.add(new BeforeMethodInterceptor());
methodInterceptors.add(new AfterMethodInterceptor());
// 2.创建目标方法
UserService userService = new UserService();
Method loginMethod = UserService.class.getMethod("login", String.class, Integer.class);
Object[] objects = {"mayikt", 666};
new DefaultMethodInvocation(methodInterceptors, userService, loginMethod, objects).process();
}
}
运行结果:
注意:实际应用中通知执行顺序如下图所示:
多个切面类同时生效时,哪个Aspect先执行是随机的,如果需要定义顺序,可以使用@Order注解修饰Aspect类。值越小,优先级越高。