前言
之前写过一篇关于AOP的文章,以为对AOP有了大概的了解,可最近使用下来,心中的疑惑越来越大,于是又开始了源码debug之旅,主要的疑惑有两个
此处吐槽一下AOP的一大堆概念,什么连接点,通知,十分好奇是不是翻译得不好
Advice与Advisor
我们经常会看到Advice、Advisor,他们代表什么呢?
Advice是通知,Advisor是增强器,每个Advisor都会持有一个Advice,这个解释看起来是不是还是很抽象,我也是这样觉得,还是用代码来解释比较好,我写了这样的一个切面,里面有一个方法,Spring为了便于管理和做一些额外的功能,会怎么包装呢?
@Aspect
@Component
public class AspectDemo {
@Pointcut("@annotation(aspectAnnotation)")
public void test(AspectAnnotation aspectAnnotation) {
}
@Before("test(aspectAnnotation)")
public void before(JoinPoint p, AspectAnnotation aspectAnnotation) {
System.out.println("before test..");
}
}
复制代码
这个参数在下文有具体的解释,大家先看个眼熟,先记住一个结论,切面中的方法会被Spring包装成一个个的Advisor和Advice
那Advisor具体长什么样子呢?它有一个很重要的实现InstantiationModelAwarePointcutAdvisorImpl,我们来看看
final class InstantiationModelAwarePointcutAdvisorImpl
implements InstantiationModelAwarePointcutAdvisor, AspectJPrecedenceInformation, Serializable {
private static final Advice EMPTY_ADVICE = new Advice() {};
// 切点,对象包含了切点的表达式,入参,beanFactory等信息
private final AspectJExpressionPointcut declaredPointcut;
// @Aspect注解所在的类的Class
private final Class> declaringClass;
// Advice的方法名
private final String methodName;
// Advice入参的参数类型
private final Class>[] parameterTypes;
// Advice对应的Method
private transient Method aspectJAdviceMethod;
// Advice生成的工厂
private final AspectJAdvisorFactory aspectJAdvisorFactory;
// 这个工厂类的实现BeanFactoryAspectInstanceFactory,在切面排序中发挥关键作用
private final MetadataAwareAspectInstanceFactory aspectInstanceFactory;
// 切面的优先级,目前被硬编码为0
private final int declarationOrder;
// @Aspect注解所在的类的类名
private final String aspectName;
// 持有的数据跟declaredPointcut类似,猜测是历史负债所做的兼容
private final Pointcut pointcut;
// Advisor持有的Advice实例
@Nullable
private Advice instantiatedAdvice;
}
复制代码
看到上面这些信息,这个类仿佛是在对我们说我从哪里来,我要做什么,比起我从哪里来,我们更关注我要做什么——Advice,Advice也是一个接口,我们看看下图他的亲人们,看名字是不是很熟悉,最下面的5个类分别对应@AfterReturning、@AfterThrowing、@After、@Around、@Before
他们都有一个共同的抽象类AbstractAspectJAdvice,先看看这个类的成员变量能更好地理解下面的代码
public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedenceInformation, Serializable {
// @Aspect注解所在的类的Class
private final Class> declaringClass;
// Advice的方法名
private final String methodName;
// Advice入参的参数类型
private final Class>[] parameterTypes;
// Advice对应的Method
protected transient Method aspectJAdviceMethod;
// 切点,对象包含了切点的表达式,入参,beanFactory等信息
private final AspectJExpressionPointcut pointcut;
// 这个工厂类的实现BeanFactoryAspectInstanceFactory,在切面排序中发挥关键作用
private final AspectInstanceFactory aspectInstanceFactory;
// @Aspect注解所在的类的类名
private String aspectName = "";
// 切面的优先级,目前被硬编码为0
private int declarationOrder;
// Advice入参的参数名
@Nullable
private String[] argumentNames;
// 当注解为@AfterThrowing且throwing值不为空时,throwing的值
@Nullable
private String throwingName;
// 当注解为@AfterReturning且returning值不为空时,returning的值
@Nullable
private String returningName;
// 当注解为@AfterReturning且returning值不为空时,返回值的Class
private Class> discoveredReturningType = Object.class;
// 当注解为@AfterThrowing且throwing值不为空时,返回值的Class
private Class> discoveredThrowingType = Object.class;
// 如果Advice对应的方法的第一个入参是JoinPoint或者ProceedingJoinPoint类型,这个值为0
private int joinPointArgumentIndex = -1;
// 如果Advice对应的方法的第一个入参是JoinPoint.StaticPart,这个值为0
private int joinPointStaticPartArgumentIndex = -1;
// Advice未绑定的参数名称及参数的排序
@Nullable
private Map argumentBindings;
private boolean argumentsIntrospected = false;
// 当注解为@AfterReturning且returning值不为空时,返回值的泛型
@Nullable
private Type discoveredReturningGenericType;
}
复制代码
再看看其中一个继承了抽象类的切面,整个类很简单,只有一个反射的调用,说明抽象类承载了大部分的功能,并且所有注解的步骤都是类似的,可以整合到一起
public class AspectJAfterAdvice extends AbstractAspectJAdvice
implements MethodInterceptor, AfterAdvice, Serializable {
public AspectJAfterAdvice(
Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
super(aspectJBeforeAdviceMethod, pointcut, aif);
}
// 反射调用真正的方法
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
@Override
public boolean isBeforeAdvice() {
return false;
}
@Override
public boolean isAfterAdvice() {
return true;
}
复制代码
看完上面琐碎的背景,我们来看一个Advice的创建过程,串联一下知识点
// 这个方法位于InstantiationModelAwarePointcutAdvisorImpl中,实例化Advice
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
return (advice != null ? advice : EMPTY_ADVICE);
}
@Override
@Nullable
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
......
AbstractAspectJAdvice springAdvice;
// 根据注解类型生成不同的通知实例
// 对应的注解就是@Around、@Before、@After、@AfterReturning、@AfterThrowing
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter:
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
// 当注解中的参数returning不为空时,设置该值
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing:
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
// 当注解中的参数throwing不为空时,设置该值
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
// 设置Advice所属的类
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
// 获取Advice的所有参数
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
// 将通知方法上的参数设置到通知中
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
复制代码
以下是解析切面注解上的参数,代码写得很难理解,我一步一步debug给大家看,还是上面那个方法,那个类有两个入参
public final synchronized void calculateArgumentBindings() {
// 如果方法没有入参,也就是不需要绑定参数,直接返回
if (this.argumentsIntrospected || this.parameterTypes.length == 0) {
return;
}
// numUnboundArgs为未计划好的参数绑定数量
int numUnboundArgs = this.parameterTypes.length;
Class>[] parameterTypes = this.aspectJAdviceMethod.getParameterTypes();
// 切面注解标识方法第一个参数要求是JoinPoint或者JoinPoint.StaticPart
// 若是@Around注解则也可以是ProceedingJoinPoint
if (maybeBindJoinPoint(parameterTypes[0]) || maybeBindProceedingJoinPoint(parameterTypes[0]) ||
maybeBindJoinPointStaticPart(parameterTypes[0])) {
numUnboundArgs--;
}
if (numUnboundArgs > 0) {
// 继续按照名称绑定参数
bindArgumentsByName(numUnboundArgs);
}
this.argumentsIntrospected = true;
}
复制代码
入参中第一个参数如果是JoinPoint、JoinPoint.StaticPart、ProceedingJoinPoint,固定排在第一位,并且 joinPointArgumentIndex或者 joinPointStaticPartArgumentIndex会被设置为0,其它入参则是未绑定参数,下文会继续进行绑定
private void bindArgumentsByName(int numArgumentsExpectingToBind) {
if (this.argumentNames == null) {
// 获取方法参数的名称
this.argumentNames = createParameterNameDiscoverer().getParameterNames(this.aspectJAdviceMethod);
}
if (this.argumentNames != null) {
// We have been able to determine the arg names.
bindExplicitArguments(numArgumentsExpectingToBind);
}
......
}
private void bindExplicitArguments(int numArgumentsLeftToBind) {
Assert.state(this.argumentNames != null, "No argument names available");
// 此属性用来存储方法未绑定的参数名称及参数的序号
this.argumentBindings = new HashMap<>();
int numExpectedArgumentNames = this.aspectJAdviceMethod.getParameterCount();
if (this.argumentNames.length != numExpectedArgumentNames) {
throw new IllegalStateException("Expecting to find " + numExpectedArgumentNames +
" arguments to bind by name in advice, but actually found " +
this.argumentNames.length + " arguments.");
}
// argumentIndexOffset表示第一个未绑定参数的顺序
int argumentIndexOffset = this.parameterTypes.length - numArgumentsLeftToBind;
for (int i = argumentIndexOffset; i < this.argumentNames.length; i++) {
// 存储未绑定的参数名称及其映射顺序
this.argumentBindings.put(this.argumentNames[i], i);
}
// Check that returning and throwing were in the argument names list if
// specified, and find the discovered argument types.
// 如果@AfterReturn
if (this.returningName != null) {
if (!this.argumentBindings.containsKey(this.returningName)) {
throw new IllegalStateException("Returning argument name '" + this.returningName +
"' was not bound in advice arguments");
}
else {
// 获取该入参的参数顺序
Integer index = this.argumentBindings.get(this.returningName);
// 设置返回值Class
this.discoveredReturningType = this.aspectJAdviceMethod.getParameterTypes()[index];
// 在返回值有泛型的情况下,设置返回值泛型
this.discoveredReturningGenericType = this.aspectJAdviceMethod.getGenericParameterTypes()[index];
}
}
// 如果是@AfterThrowing
if (this.throwingName != null) {
if (!this.argumentBindings.containsKey(this.throwingName)) {
throw new IllegalStateException("Throwing argument name '" + this.throwingName +
"' was not bound in advice arguments");
}
else {
// 获取该入参的参数顺序
Integer index = this.argumentBindings.get(this.throwingName);
// 设置异常Class
this.discoveredThrowingType = this.aspectJAdviceMethod.getParameterTypes()[index];
}
}
// configure the pointcut expression accordingly.
configurePointcutParameters(this.argumentNames, argumentIndexOffset);
}
复制代码
// 这个方法会将所有未绑定参数的名字和类型存储在切点中,待后续使用
private void configurePointcutParameters(String[] argumentNames, int argumentIndexOffset) {
int numParametersToRemove = argumentIndexOffset;
if (this.returningName != null) {
numParametersToRemove++;
}
if (this.throwingName != null) {
numParametersToRemove++;
}
String[] pointcutParameterNames = new String[argumentNames.length - numParametersToRemove];
Class>[] pointcutParameterTypes = new Class>[pointcutParameterNames.length];
Class>[] methodParameterTypes = this.aspectJAdviceMethod.getParameterTypes();
int index = 0;
for (int i = 0; i < argumentNames.length; i++) {
if (i < argumentIndexOffset) {
continue;
}
if (argumentNames[i].equals(this.returningName) ||
argumentNames[i].equals(this.throwingName)) {
continue;
}
pointcutParameterNames[index] = argumentNames[i];
pointcutParameterTypes[index] = methodParameterTypes[i];
index++;
}
this.pointcut.setParameterNames(pointcutParameterNames);
this.pointcut.setParameterTypes(pointcutParameterTypes);
}
复制代码
Advisor的排序
如果一个方法打了多个切面注解,这个方法就会对应多个Advisor,这个时候哪个Advisor先执行,哪个Advisor后执行就是一个很大的问题,这个问题很严重,千万别小看
到达排序的调用链很深,我们直接到排序相关的方法
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#sortAdvisors
private static final Comparator DEFAULT_PRECEDENCE_COMPARATOR = new AspectJPrecedenceComparator();
@Override
protected List sortAdvisors(List advisors) {
// 使用PartiallyComparableAdvisorHolder对Advisor进行了包装,加入了DEFAULT_PRECEDENCE_COMPARATOR这个比较器
List partiallyComparableAdvisors = new ArrayList<>(advisors.size());
for (Advisor advisor : advisors) {
partiallyComparableAdvisors.add(
new PartiallyComparableAdvisorHolder(advisor, DEFAULT_PRECEDENCE_COMPARATOR));
}
List sorted = PartialOrder.sort(partiallyComparableAdvisors);
if (sorted != null) {
List result = new ArrayList<>(advisors.size());
for (PartiallyComparableAdvisorHolder pcAdvisor : sorted) {
result.add(pcAdvisor.getAdvisor());
}
return result;
}
else {
return super.sortAdvisors(advisors);
}
}
复制代码
public AspectJPrecedenceComparator() {
// 构造器中加入了一个比较器
this.advisorComparator = AnnotationAwareOrderComparator.INSTANCE;
}
@Override
public int compare(Advisor o1, Advisor o2) {
// 这个方法有两重比较,首先用advisorComparator进行比较
int advisorPrecedence = this.advisorComparator.compare(o1, o2);
// 顺序相同,且来源同一aspect,调用comparePrecedenceWithinAspect再次比较
if (advisorPrecedence == SAME_PRECEDENCE && declaredInSameAspect(o1, o2)) {
advisorPrecedence = comparePrecedenceWithinAspect(o1, o2);
}
return advisorPrecedence;
}
复制代码
@Override
public int compare(@Nullable Object o1, @Nullable Object o2) {
return doCompare(o1, o2, null);
}
private int doCompare(@Nullable Object o1, @Nullable Object o2, @Nullable OrderSourceProvider sourceProvider) {
// 两者之一为PriorityOrdered,谁是PriorityOrdered,谁的优先级高,在Advisor的比较中,这个是不起作用的
// 因为Advisor都被包装成了InstantiationModelAwarePointcutAdvisorImpl,这个类没有实现PriorityOrdered
boolean p1 = (o1 instanceof PriorityOrdered);
boolean p2 = (o2 instanceof PriorityOrdered);
if (p1 && !p2) {
return -1;
}
else if (p2 && !p1) {
return 1;
}
// 两者都是Ordered,根据getOrder()返回的值做比较,值越小优先级越高
int i1 = getOrder(o1, sourceProvider);
int i2 = getOrder(o2, sourceProvider);
return Integer.compare(i1, i2);
}
复制代码
getOrder()的调用链比较深,此处先说结论
以上的比较中,注解返回的值和接口返回的值是一起比较,并没有哪一个比较优先的说法
getOrder()的调用链
org.springframework.core.OrderComparator#getOrder
org.springframework.core.OrderComparator#findOrder
org.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl#getOrder
org.springframework.aop.aspectj.annotation.BeanFactoryAspectInstanceFactory#getOrder
下面这个是比较关键的方法
@Override
public int getOrder() {
// 在IOC容器中查找切面类,切面类是指打了@Aspect注解的类,这个赋值是在形成Advisor的时候赋好的
Class> type = this.beanFactory.getType(this.name);
if (type != null) {
// 如果切面类实现了Ordered或者PriorityOrdered,直接获取接口的返回值
if (Ordered.class.isAssignableFrom(type) && this.beanFactory.isSingleton(this.name)) {
return ((Ordered) this.beanFactory.getBean(this.name)).getOrder();
}
// 如果没有实现Ordered或者PriorityOrdered,则获取@Order或者@Priority注解中的值
// 如果注解中也没有值,则返回Integer.MAX_VALUE
return OrderUtils.getOrder(type, Ordered.LOWEST_PRECEDENCE);
}
//
return Ordered.LOWEST_PRECEDENCE;
}
复制代码
以上的比较是基于不同的切面进行的比较,如果同一个切面,比如一个切面中有多个@After的方法,要如何比较呢?这个比较有两个步骤
org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisors
org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisorMethods
private List getAdvisorMethods(Class> aspectClass) {
final List methods = new ArrayList<>();
ReflectionUtils.doWithMethods(aspectClass, method -> {
// 除去Pointcut注解
if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
methods.add(method);
}
}, ReflectionUtils.USER_DECLARED_METHODS);
if (methods.size() > 1) {
// 对所有advisors方法进行排序
methods.sort(METHOD_COMPARATOR);
}
return methods;
}
private static final Comparator METHOD_COMPARATOR;
static {
// 按照@Around、@Before、@After、@AfterReturning、@AfterThrowing的顺序
Comparator adviceKindComparator = new ConvertingComparator<>(
new InstanceComparator<>(
Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
(Converter) method -> {
AspectJAnnotation> ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
return (ann != null ? ann.getAnnotation() : null);
});
Comparator methodNameComparator = new ConvertingComparator<>(Method::getName);
METHOD_COMPARATOR = adviceKindComparator.thenComparing(methodNameComparator);
}
复制代码
当前位置
不再有效,因为JDK不再有效返回在源代码中声明方法的顺序,仅靠SpirngAOP是无法保证排序的,此外,如果类被混淆、JVM或者编译器不同,其结果也可能会改变private int comparePrecedenceWithinAspect(Advisor advisor1, Advisor advisor2) {
// 其中一个是否存在@After注解
boolean oneOrOtherIsAfterAdvice =
(AspectJAopUtils.isAfterAdvice(advisor1) || AspectJAopUtils.isAfterAdvice(advisor2));
int adviceDeclarationOrderDelta = getAspectDeclarationOrder(advisor1) - getAspectDeclarationOrder(advisor2);
// 其中有一个是after通知,declarationOrder大的优先级高
if (oneOrOtherIsAfterAdvice) {
if (adviceDeclarationOrderDelta < 0) {
return LOWER_PRECEDENCE;
}
else if (adviceDeclarationOrderDelta == 0) {
return SAME_PRECEDENCE;
}
else {
return HIGHER_PRECEDENCE;
}
}
// 两个都不是after通知,declarationOrder小的优先级高
else {
if (adviceDeclarationOrderDelta < 0) {
return HIGHER_PRECEDENCE;
}
else if (adviceDeclarationOrderDelta == 0) {
return SAME_PRECEDENCE;
}
else {
return LOWER_PRECEDENCE;
}
}
}
复制代码
Advice的参数传递
调用链还是很深,只讲关键的方法
org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept
org.springframework.aop.framework.CglibAopProxy.CglibMethodInvocation#proceed
org.springframework.aop.framework.ReflectiveMethodInvocation#proceed
org.springframework.aop.interceptor.ExposeInvocationInterceptor#invoke
org.springframework.aop.framework.CglibAopProxy.CglibMethodInvocation#proceed
org.springframework.aop.framework.ReflectiveMethodInvocation#proceed
org.springframework.aop.aspectj.AspectJAroundAdvice#invoke
org.springframework.aop.aspectj.AbstractAspectJAdvice#invokeAdviceMethod(org.aspectj.lang.JoinPoint, org.aspectj.weaver.tools.JoinPointMatch, java.lang.Object, java.lang.Throwable)
org.springframework.aop.aspectj.AbstractAspectJAdvice#invokeAdviceMethodWithGivenArgs
protected Object[] argBinding(JoinPoint jp, @Nullable JoinPointMatch jpMatch,
@Nullable Object returnValue, @Nullable Throwable ex) {
// 这个方法上面已经解读过,重复调用一次而已
calculateArgumentBindings();
// 根据Advice入参的数量创建数组,这个数组是真正进行反射调用时的入参
Object[] adviceInvocationArgs = new Object[this.parameterTypes.length];
int numBound = 0;
// this.joinPointArgumentIndex不为-1,表示Advice对应的方法的第一个入参是JoinPoint或者ProceedingJoinPoint类型
if (this.joinPointArgumentIndex != -1) {
adviceInvocationArgs[this.joinPointArgumentIndex] = jp;
numBound++;
}
// this.joinPointStaticPartArgumentIndex不为-1.表示Advice对应的方法的第一个入参是JoinPoint.StaticPart
else if (this.joinPointStaticPartArgumentIndex != -1) {
adviceInvocationArgs[this.joinPointStaticPartArgumentIndex] = jp.getStaticPart();
numBound++;
}
if (!CollectionUtils.isEmpty(this.argumentBindings)) {
if (jpMatch != null) {
// 根据切点进行参数的匹配
PointcutParameter[] parameterBindings = jpMatch.getParameterBindings();
for (PointcutParameter parameter : parameterBindings) {
// 根据参数的名字获取入参的顺序
String name = parameter.getName();
Integer index = this.argumentBindings.get(name);
adviceInvocationArgs[index] = parameter.getBinding();
numBound++;
}
}
// 当注解为@AfterReturning且returning值不为空时,进行赋值
if (this.returningName != null) {
Integer index = this.argumentBindings.get(this.returningName);
adviceInvocationArgs[index] = returnValue;
numBound++;
}
// 当注解为@AfterThrowing且throwing值不为空时,进行赋值
if (this.throwingName != null) {
Integer index = this.argumentBindings.get(this.throwingName);
adviceInvocationArgs[index] = ex;
numBound++;
}
}
if (numBound != this.parameterTypes.length) {
throw new IllegalStateException("Required to bind " + this.parameterTypes.length +
" arguments, but only bound " + numBound + " (JoinPointMatch " +
(jpMatch == null ? "was NOT" : "WAS") + " bound in invocation)");
}
return adviceInvocationArgs;
}
复制代码
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
Object[] actualArgs = args;
// 如果增强方法没有参数,将actualArgs设置为null
if (this.aspectJAdviceMethod.getParameterCount() == 0) {
actualArgs = null;
}
try {
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
// 反射增强方法
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
}
......
}
复制代码
至此,文章开头提到的疑惑稍微有了点眉目