自学内容网 自学内容网

Spring AOP源码分析

概要

以下是用于debug Spring AOP源码得测试代码:

@Aspect//声明这是一个切面
@Component//声明这是一个组件
/**
 * 执行顺序
 * @Around进入环绕通知...
 * @Before进入前置通知:[]
 * 进入实现类 work.....
 * @Around方法执行耗时>>>>>: 1001
 * @After进入后置通知...
 * @AfterReturning进入最终通知...End!
 */
public class SlaverAspect {

//环绕通知(连接到切入点开始执行,下一步进入前置通知,在下一步才是执行操作方法)
@Around(value = "pointCut()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("@Around进入环绕通知...");
long startTime = System.currentTimeMillis();
//调用了下一个拦截器,递归调用ReflectiveMethodInvocation#proceed
joinPoint.proceed();
long endTime = System.currentTimeMillis();
System.out.println(String.format("@Around方法执行耗时>>>>>: %s", endTime - startTime));
}

//前置通知(进入环绕后执行,下一步执行方法)
@Before(value = "pointCut()")
public void before(JoinPoint joinPoint) {
System.out.println("@Before进入前置通知:" + Arrays.toString(joinPoint.getArgs()));
}

//异常通知(出错时执行)
@AfterThrowing(value = "pointCut()", throwing = "ex")
public void afterThrowing(JoinPoint joinPoint, Throwable ex) {
System.out.println("@AfterThrowing进入异常通知" + Arrays.toString(joinPoint.getArgs()));

}

//后置通知(返回之前执行)
@After(value = "pointCut()")
public void after() {
System.out.println("@After进入后置通知...");
}

//最终通知(正常返回通知,最后执行,出现异常)
@AfterReturning(value = "pointCut()")
public void afterReturning() {
System.out.println("@AfterReturning进入最终通知...End!");
}

//定义一个切入点 后面的通知直接引入切入点方法pointCut即可
//参数:
//第一个”*“符号;表示返回值的类型任意
//.*(..)表示任何方法名,括号表示参数,两个点表示任何参数类型
@Pointcut(value = "execution(* com.spring.test.aop.impl.SlaverImpl.*(..))")
public void pointCut() {
System.out.println("@进入切点...");
}

}

测试类

public interface Slaver {
void work();
}
@Service
public class SlaverImpl implements Slaver {
//用来织入AOP的通知方法
@Override
public void work() {
System.out.println("进入实现类work.....");
try {
Thread.sleep(1000);
//此处决定拦截器的走向
//int  s=1/0;
} catch (InterruptedException e) {
e.printStackTrace();
}

}

}

测试入口

public class Main {

public static void main(String[] args) throws InterruptedException {
ApplicationContext context =
new ClassPathXmlApplicationContext("classpath*:application-aop.xml");
Slaver slaver = (Slaver) context.getBean("slaverImpl");
//使用代理调用了JdkDynamicAopProxy.invoke
slaver.work();
System.out.printf(slaver.getClass().getName());
//Thread.sleep(Integer.MAX_VALUE);
System.out.println("over>>>>>>>>>>");

Cglib动态代理(不实现接口)
//SlaverImpl slaver = (SlaverImpl) context.getBean("slaverImpl");
////使用代理调用了JdkDynamicAopProxy.invoke
//slaver.work();


//System.out.println(">>>>>>>>>>"+slaver);
//AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Object.class);
//ApplicationContext context2 =
//new FileSystemXmlApplicationContext("classpath*:application-aop.xml");
}
}

Bean后置处理器

在IOC容器主流程中:

@Override
public void refresh() throws BeansException, IllegalStateException {
// synchronized块锁(monitorenter --monitorexit)
// 不然 refresh() 还没结束,又来个启动或销毁容器的操作
// startupShutdownMonitor就是个空对象,锁
synchronized (this.startupShutdownMonitor) {
//1、【准备刷新】,设置了几个变量,也是准备工作
prepareRefresh();   //  ===>
// 2、【获得新的bean工厂】关键步骤,重点!
//2.1、关闭旧的 BeanFactory
//2.2、创建新的 BeanFactory(DefaluListbaleBeanFactory)
//2.3、解析xml/加载 Bean 定义、注册 Bean定义到beanFactory(不初始化)
//2.4、返回全新的工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  //  ===> 
//3、【bean工厂前置操作 】为BeanFactory配置容器特性
// 例如类加载器、表达式解析器、注册默认环境bean、后置管理器
prepareBeanFactory(beanFactory);   // ===>
try {
// 4、【bean工厂后置操作】此处为空方法,如果子类需要,自己去实现
postProcessBeanFactory(beanFactory);  // ===> 空的!
//5、【调用bean工厂后置处理器】,开始调用我们自己实现的接口
//目标:
//调用顺序一:先bean定义注册后置处理器
//调用顺序二:后bean工厂后置处理器
invokeBeanFactoryPostProcessors(beanFactory);  // ===> 

//6、【注册bean后置处理器】只是注册,但是还不会调用
//逻辑:找出所有实现BeanPostProcessor接口的类,分类、排序、注册
registerBeanPostProcessors(beanFactory);  // ===>  关键点
// Initialize message source for this context.
//7、【初始化消息源】国际化问题i18n,参照https://nacos.io/
initMessageSource(); // ===> 就是往factory加了个single bean

// Initialize event multicaster for this context.
//8、【初始化事件广播器】初始化自定义的事件监听多路广播器
// 如果需要发布事件,就调它的multicastEvent方法
// 把事件广播给listeners,其实就是起一个线程来处理,把Event扔给listener处理
// (可以通过 SimpleApplicationEventMulticaster的代码来验证)
initApplicationEventMulticaster(); // ===> 同样,加了个bean
// 9、【刷新】这是个protected空方法,交给具体的子类来实现
//  可以在这里初始化一些特殊的 Bean
// (在初始化 singleton beans 之前)
onRefresh();  // ===> 空的
//10、【注册监听器】,监听器需要实现 ApplicationListener 接口
// 也就是扫描这些实现了接口的类,给他放进广播器的列表中
// 其实就是个观察者模式,广播器接到事件的调用时,去循环listeners列表,
// 挨个调它们的onApplicationEvent方法,把event扔给它们。
registerListeners();  // ===> 观察者模式
//11、 【结束bean工厂初始化操作】
//1、初始化所有的 singleton beans,反射生成对象/填充
//2、 调用Bean的前置处理器和后置处理器
// 关键点:getBean方法里完成
finishBeanFactoryInitialization(beanFactory);  // ===>  关键点
// 12、结束refresh操作
// 发布事件与清除上下文环境
finishRefresh();


} catch (BeansException ex) {
。。。
} finally {
。。。
}
}
}

在上面调用得方法finishBeanFactoryInitialization
在这里插入图片描述
触发了bean的后置处理器的调用
在这里插入图片描述
其中在后置处理器org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization方法中

//如果当前的bean适合被代理,则需要包装指定的bean
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
if (bean != null) {
// 根据给定的bean的class和name构建一个key
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {

// 如果当前的bean适合被代理,则需要包装指定的bean
// aop:注意看这个bean,这还是SlaverImpl本尊,那么进去以后,情况变了~
return wrapIfNecessary(bean, beanName, cacheKey);  // ===>  aop 进!
}
}
return bean;
}
//1、判断当前bean是否已经生成过代理对象
//2、拿到切面类中的所有增强方法(拦截器:环绕、前置、后置等)
//3、生成代理对象
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 判断是否为空    否在TargetSource缓存中存在
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// advisedBeans缓存了不需要代理的bean(为false的),如果缓存中存在,则可以直接返回
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
//Infrastructure基础设施
// 判断bean是否为Spring自带bean,如果是,不用进行代理的
// shouldSkip()则用于判断当前bean是否应该被略过
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
// 对当前bean进行缓存
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}

//AOP:   【关键点 1 】
// 找到哪些aspect的execution能匹配上当前bean
// 匹配上的话列出前后和置换的方法(拦截器:环绕、前置、后置等),并且!!排好顺序
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);  // ===> debug进
//debug后,仔细看一下上面这个数组内的值,其实就是SlaverAspect里的匹配上的方法信息!
//如果有匹配上的方法,就生成代理对象【关键点!】
if (specificInterceptors != DO_NOT_PROXY) {
// 允许创建代理对象的,设置为true
this.advisedBeans.put(cacheKey, Boolean.TRUE);

// 【关键节点 2 】
// 开始创建AOP代理
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); // ===>
// 缓存生成的代理bean的类型,并且返回生成的代理bean
this.proxyTypes.put(cacheKey, proxy.getClass());
//此处返回的代理和在Main函数中返回的是一样的
//说明此处代理成功创建
return proxy;
}
//如果拿到的增强方法为空,缓存起来(使用false标记不需要代理)
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
 @Nullable Object[] specificInterceptors, TargetSource targetSource) {
//为true,DefaultListableBeanFactory
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
//标记一下,当前的bean具备创建代理的资格
// 其实就是在BD设置了属性setAttribute("originalTargetClass",bean的class),===>
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);  // ===>
}
//创建一个默认的代理工厂DefaultAopProxyFactory,注意:父类无参构造器
ProxyFactory proxyFactory = new ProxyFactory();

//proxyFactory通过复制配置进行初始化
//this为AbstractAutoProxyCreator对象,说明AbstractAutoProxyCreator继承参数实际类型
proxyFactory.copyFrom(this);  // ===> 其实就是设置了一堆值
/**
 * true
 *目标对象没有接口(只有实现类) – 使用CGLIB代理机制
 * false
 * 目标对象实现了接口 – 使用JDK代理机制(代理所有实现了的接口)
 */

//默认值为false,为true,使用CGLIB,
if (!proxyFactory.isProxyTargetClass()) {
//来判断@EnableAspectJAutoProxy注解或者XML的proxyTargetClass参数(true或者false)
//也就是:用户有没有明确指定什么方式生成代理
// 我们没指定,此处false
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
} else {
//评估接口的合理性,一些内部回调接口,比如InitializingBean等不要,我们自己的加入proxyFactory
evaluateProxyInterfaces(beanClass, proxyFactory);  // ===>
}
}
// 把把前面我们过滤出来的那些切面方法,转成Advisor数组
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
//加入到代理工厂
proxyFactory.addAdvisors(advisors);
//设置要代理的类(目标类)
proxyFactory.setTargetSource(targetSource);
//子类实现, 定制代理
customizeProxyFactory(proxyFactory);
//是否还允许修改通知,缺省值为false
proxyFactory.setFrozen(this.freezeProxy);
//设置预过滤
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}

//【关键点!】proxyFactory携带了aop里配置的各种切面方法等等,由它来创建代理
return proxyFactory.getProxy(getProxyClassLoader());   // 代理类诞生的地方,这里真正生产jdk还是cglib的动态代理
}

上面就是在bean的后置处理器中完成动态代理的创建过程,其中的类关系图如下:
在这里插入图片描述

代理对象调用使用责任链模式

public static void main(String[] args) throws InterruptedException {
ApplicationContext context =
new ClassPathXmlApplicationContext("classpath*:application-aop.xml");
Slaver slaver = (Slaver) context.getBean("slaverImpl");
//使用代理调用了JdkDynamicAopProxy.invoke
slaver.work();
System.out.printf(slaver.getClass().getName());
//Thread.sleep(Integer.MAX_VALUE);
System.out.println("over>>>>>>>>>>");
}

测试代码执行到work方法时,会直接进入到org.springframework.aop.framework.JdkDynamicAopProxy#invoke

//1、调用增强方法
//2、反射调用目标方法
//重点关注:getInterceptorsAndDynamicInterceptionAdvice责任链方法
//         和invocation.proceed()方法(开始调用)
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
//一堆判断和加载,拖到最下面,看责任链部分,核心在那里。
Object oldProxy = null;
boolean setProxyContext = false;
//获取目标资源,此处就是slaverImpl,debug变量值试试
TargetSource targetSource = this.advised.targetSource;
Object target = null;

try { 
//当前方法是否等于Equals,如果是,则重写
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
//当前方法是否等于HashCode,如果是,则重写
} else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode();
//方法声明类是否等于DecoratingProxy
} else if (method.getDeclaringClass() == DecoratingProxy.class) {
//使用反射直接进行调用目标资源
return AopProxyUtils.ultimateTargetClass(this.advised);
//方法声明是否接口 、或者是否Advised类型
} else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// 用代理配置对ProxyConfig进行服务调用。。。
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}

Object retVal;
//如果暴露;就放到ThreadLocal,默认不暴
if (this.advised.exposeProxy) {
//放到ThreadLocal
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}

//目标资源;对应业务实现类,这是我们的真身(SlaverImpl)
target = targetSource.getTarget();
//目标类;对应业务实现类
Class<?> targetClass = (target != null ? target.getClass() : null);
          //【关键点 1 】构建责任链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);  // ===> a
//  如果为空,则直接调用target的method
if (chain.isEmpty()) {
//如果没有拦截器,直接调用
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);  // 直接执行
} else {

//proxy代理对象
//target是目标类
//targetClass是目标类的class
//method是目标方法
//args是对应的方法参数
//chain是对应的拦截器
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
//!!!责任链即将开始调用的入口~~~
retVal = invocation.proceed();  // ===> 【关键点 2 】
}
//以下方法,在责任链执行完成后,才会跑到,就一些收尾工作
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
} else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
} finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// 重新设置下ThreadLocal
AopContext.setCurrentProxy(oldProxy);
}
}
}

org.springframework.aop.framework.ReflectiveMethodInvocation#proceed

//开始责任链模式;遍历拦截器链,调用每个拦截器的invoke方法
@Override
@Nullable
public Object proceed() throws Throwable {
//1、currentInterceptorIndex    索引,-1开始并提前递增
//2、this.interceptorsAndDynamicMethodMatchers,就是前面的拦截方法集合,list
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
//如果执行到链条的末尾 则开始调用原始方法,
//第一次肯定进不来这里,由before执行过后才会进来!执行完后,会回到before
return invokeJoinpoint();  // ===>  反射执行业务方法,也就是我们的work方法
}
//自增。这个索引从-1开始的,所以先++
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

//判断类型执行invoke或proceed
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
//强制转换
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
// 动态判断拦截器是否匹配
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
} else {
// 不匹配会递归调用拦截链的下一个拦截器
return proceed();
}
} else {

// 开始调用链第一环,为 ExposeInvocationInterceptor
// 也就是spring自动帮我们加上的,上下传递 MethodInvocation
// 注意这个参数:this 。
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); // ===>
}
}

org.springframework.aop.interceptor.ExposeInvocationInterceptor#invoke

//暴露调用拦截器方法,核心invocation.set(mi);
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
//将MethodInvocation mi 设置到 ThreadLocal invocation 里面,拿的时候也可以使用上面的 方法currentInvocation
MethodInvocation oldInvocation = invocation.get();
//第一环!expose
// 先干自己的活,本地线程局部变量,方法currentInvocation可以获取
invocation.set(mi);
try {
// 然后,继续调责任链的proceed推动链条前进!
//注意这个mi,上面传来的是 this,意味着,又回到了上面继续 proceed
// 回去以后,index会增加,将执行责任链的下一环,依次推进……
return mi.proceed();  // ===> debug into , 结果回去了~
}
finally {
//最后执行,  责任链,递归调用结束~~~完美!
invocation.set(oldInvocation);
}
}

上面可以看出,每次都会调用MethodInvocation proceed()方法,从而会推进责任链方法进行推进,比如前置通知
org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
//before,先反射执行自己的逻辑
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
//然后,责任链,
return mi.proceed();  // 执行完还会回来的!
}

以上就是代理方法的执行流程。


原文地址:https://blog.csdn.net/weixin_42612223/article/details/140517287

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!