概念
- 切面Aspect
- 连接点Joint point
- 切入点Pointcut
- 通知Advice
- 目标对象Target
- 织入Weave:指将切面应用到目标对象,并导致代理对象创建的过程
在【目标对象】中定位【切入点】,【织入】对应的【通知】,就变成了【代理对象】
类型
- 前置通知:在方法执行前通知
- 后置通知:在方法正常执行完成进行通知,可以访问到方法的返回值
- 环绕通知:可以将要执行的方法(point.proceed())进行包裹执行,可以在前后添加需要执行的操作
- 异常通知:在方法出现异常时进行通知,可以访问到异常对象,且可以指定在出现特定异常时在执行通知
- 方法执行后通知: 在目标方法执行后无论是否发生异常,执行通知,不能访问目标方法的返回值
源码
解析XML
以XML配置为例:
<aop:config>
<aop:aspect ref="myAdvice">
<-- method : 指定通知类中的增强功能方法 -->
<-- pointcut : 指定切入点,需要通过表达式来指定 -->
<aop:before method="log" pointcut="execution(void demo.services.impl.DemoServiceImpl.hello(*))"/>
</aop:aspect>
</aop:config>
根据 Namespace 在 spring.handler 找到对应标签的 NamespaceHandler,调用init()
方法
<aop:config>
标签找到对应的AopNamespaceHandler
,init()
方法注册了多个解析器
<aop:config>
标签对应的解析器就是ConfigBeanDefinitionParser
,执行parse
方法解析
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compositeDef);
// 向IoC容器中注册 AspectJAwareAdvisorAutoProxyCreator 类对应的 BeanDefinition:(用于创建AOP代理对象的)
configureAutoProxyCreator(parserContext, element);
// 获取<aop:config>标签的子标签<aop:aspect>、<aop:advisor> 、<aop:pointcut>
List<Element> childElts = DomUtils.getChildElements(element);
for (Element elt: childElts) {
// 获取子标签的节点名称或者叫元素名称
String localName = parserContext.getDelegate().getLocalName(elt);
switch (localName) {
case POINTCUT -> parsePointcut(elt, parserContext);
case ADVISOR -> parseAdvisor(elt, parserContext);
case ASPECT -> parseAspect(elt, parserContext);
}
}
parserContext.popAndRegisterContainingComponent();
return null;
}
<aop:point>
标签,parsePointcut
方法注册一个 AspectJExpressionPointcut 类对应的BeanDefinition对象,处理 pointcut<aop:advisor>
标签,parseAdvisor
方法注册一个 DefaultBeanFactoryPointcutAdvisor 类对应的BeanDefinition对象,处理 advisor<aop:aspect>
标签,parseAspect
创建多个BeanBeanDefinition- 创建MethodLocatingFactoryBean的BeanDefinition对象:用于获取Advice增强类的Method对象
- 创建SimpleBeanFactoryAwareAspectInstanceFactory的BeanDefinition:用于创建增强类的实例
- 以上的两个BeanDefinition的作用主要是通过反射调用Advice对象的指定方法
method.invoke(obj,args)
- 创建通知增强类的BeanDefinition对象,根据通知类型不同,分别创建对应的BeanDefinition
- 前置通知:AspectJMethodBeforeAdvice
- 后置通知:AspectJAfterAdvice
- 方法执行后通知:AspectJAfterReturningAdvice
- 异常通知:AspectJAfterThrowingAdvice
- 环绕通知:AspectJAroundAdvice
- 创建AspectJPointcutAdvisor类的BeanDefinition对象,AspectJPointcutAdvisor的构造函数的参数就是配置的通知增强类(前置通知、后置通知、方法执行后通知、异常通知、环绕通知)
一个<aop:aspect>
对应一个切面,这里配置了<aop:aspect>
,所以执行parseAspect
方法
创建代理对象
AspectJAwareAdvisorAutoProxyCreator
的父类AbstractAutoProxyCreator
实现了BeanPostProcessor
接口,会在实例init
初始化方法执行完后调用postProcessAfterInitialization
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyBeanReferences.remove(cacheKey) != bean) {
// 如果有必要就产生代理对象
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// 找到符合条件的拦截器
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 如果拦截器不为空
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理对象
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
getAdvicesAndAdvisorsForBean
找到符合Bean的拦截器,
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 找到符合条件的Advisor
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
// 如果没有找到,返回空数组
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
// 返回Advisor
return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 找到候选的Advisor(Advisor的实现类)
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 筛选符合条件的Advisor
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
findAdvisorsThatCanApply
调用AopUtil#findAdvisorsThatCanApply
筛选符合条件的Advisor。
AopUtil#findAdvisorsThatCanApply
调用canApply
方法判断是否适用当前类。canApply
方法有多个重载方法,最终调用以下的canApply
方法
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor ia) {
return ia.getClassFilter().matches(targetClass);
}
// 如果Advisor是PointcutAdvisor
// AspectJPointcutAdvisor 实现了 PointcutAdvisor 接口
else if (advisor instanceof PointcutAdvisor pca) {
// AspectJPointcutAdvisor#getPointcut获取到到是ComposablePointcut
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
return true;
}
}
在XML解析时,会注册AspectJPointcutAdvisor
类的BeanDefinition,内部的pointcut
是一个ComposablePointcut
(组合PointCut),其ClassFilter
和MethodMatcher
其实是AspectJExpressionPointcut
的ClassFilter
和MethodMatcher
。AspectJExpressionPointcut
是在解析XML时注册的,解析切入点表达式。
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
// pointcut的类过滤器判断目标类是否符合
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
// pointcut的方法匹配器
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher iamm) {
introductionAwareMethodMatcher = iamm;
}
Set<Class<?>> classes = new LinkedHashSet<>();
if (!Proxy.isProxyClass(targetClass)) {
classes.add(ClassUtils.getUserClass(targetClass));
}
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
for (Class<?> clazz : classes) {
// 通过反射获得目标类的方法
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
// 遍历方法
for (Method method : methods) {
// 通过方法匹配来判断
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
AopUtil#canApply
方法中,通过ClassFilter
和MethodMatcher
方法的匹配来判断是否适用
createProxy
方法调用了buildProxy
,这个方法里通过代理工厂来创建代理对象
private Object buildProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource, boolean classOnly) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory clbf) {
AutoProxyUtils.exposeTargetClass(clbf, beanName, beanClass);
}
// 创建代理工厂
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (proxyFactory.isProxyTargetClass()) {
// Explicit handling of JDK proxy targets and lambdas (for introduction advice scenarios)
if (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {
// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
for (Class<?> ifc : beanClass.getInterfaces()) {
proxyFactory.addInterface(ifc);
}
}
}
else {
// No proxyTargetClass flag enforced, let's apply our default checks...
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 构建Advisor
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// Use original ClassLoader if bean class not locally loaded in overriding class loader
ClassLoader classLoader = getProxyClassLoader();
if (classLoader instanceof SmartClassLoader smartClassLoader && classLoader != beanClass.getClassLoader()) {
classLoader = smartClassLoader.getOriginalClassLoader();
}
return (classOnly ? proxyFactory.getProxyClass(classLoader) : proxyFactory.getProxy(classLoader));
}
调用了ProxyFactory#getProxy()
方法
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
动态代理有Cglib和JDK两种,所以createAopProxy()
会判断创建ObjenesisCglibAopProxy
还是JdkDynamicAopProxy
对象
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 是否优化(强制使用cglib),默认false
// 是否直接代理目标类,默认false
// 没有实现接口,或者只实现了SpringProxy接口
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// cglib动态代理
return new ObjenesisCglibAopProxy(config);
}
else {
// jdk动态代理
return new JdkDynamicAopProxy(config);
}
}
如果目标类实现了接口(除SpringProxy外),在默认情况下会采用JDK动态代理实现AOP,然后调用getProxy
方法
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
return Proxy.newProxyInstance(determineClassLoader(classLoader), this.cache.proxiedInterfaces, this);
}
执行代理对象
而JdkDynamicAopProxy本身也是InvocationHandler
,创建代理对象时把自己当作InvocationHandler
参数传进去,所以在调用方法时,会执行JdkDynamicAopProxy#invoke()
方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
// equals方法
if (!this.cache.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
// hashCode方法
else if (!this.cache.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
// 如果配置 exposeProxy 为 true,则把当前代理对象放到线程ThreadLocal
// 当想要自己调自己同时代理不失效,可以配为true
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
// 获取当前方法的拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fall back on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
// 如果拦截器链为空直接反射调用目标方法
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
// 构建MethodInvocation
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
// 通过拦截器链执行连接点
retVal = invocation.proceed();
}
// 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.class && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
if (KotlinDetector.isSuspendingFunction(method)) {
return COROUTINES_FLOW_CLASS_NAME.equals(new MethodParameter(method, -1).getParameterType().getName()) ?
CoroutinesUtils.asFlow(retVal) : CoroutinesUtils.awaitSingleOrNull(retVal, args[args.length - 1]);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
获取拦截器链,AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice
方法内部调用了DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice
方法
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
// 这里是DefaultAdvisorAdapterRegistry对象
// 注册了几个适配器:MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter、ThrowsAdviceAdapter
// 适配器用于将通知增强类包装成拦截器,在执行代理对象时也是调用拦截器
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
Advisor[] advisors = config.getAdvisors();
List<Object> interceptorList = new ArrayList<>(advisors.length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
for (Advisor advisor : advisors) {
// 如果advisor是PointcutAdvisor
// 解析时注册了AspectJPointcutAdvisor,所以AspectJPointcutAdvisor会走这个if分支
if (advisor instanceof PointcutAdvisor pointcutAdvisor) {
// Add it conditionally.
// ClassFilter匹配目标类
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
// MethodMatcher匹配目标方法
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
if (mm instanceof IntroductionAwareMethodMatcher iamm) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
match = iamm.matches(method, actualClass, hasIntroductions);
}
else {
match = mm.matches(method, actualClass);
}
// 如果匹配成功
if (match) {
// 调用DefaultAdvisorAdapterRegistry#getInterceptors获取拦截器
// 这里将通知增强类包装成拦截器
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor ia) {
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
DefaultAdvisorAdapterRegistry#getInterceptors
方法,将通知增强类包装成了拦截器
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<>(3);
// 获取通知增强器对象
Advice advice = advisor.getAdvice();
// 如果通知增强器对象是MethodInterceptor(AspectJAroundAdvice、AspectJAfterAdvice、AspectJAfterThrowingAdvice),直接添加到集合
if (advice instanceof MethodInterceptor methodInterceptor) {
interceptors.add(methodInterceptor);
}
// 遍历适配器
// 也就是注册的MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter、ThrowsAdviceAdapter
for (AdvisorAdapter adapter : this.adapters) {
// 如果适配器支持这个通知增强器对象,也就是MethodBeforeAdvice、AfterReturningAdvice、ThrowsAdvice
if (adapter.supportsAdvice(advice)) {
// 把通知增强器对象包装成拦截器对象,添加到集合
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
// 返回拦截器数组
return interceptors.toArray(new MethodInterceptor[0]);
}
在解析XML时,如果是环绕通知、后置通知、异常通知,注册的通知增强器对象,直接实现了MethodInterceptor接口
- AspectJAroundAdvice
- AspectJAfterAdvice
- AspectJAfterThrowingAdvice
获取拦截器链,把通知增强器对象(MethodBeforeAdvice、AfterReturningAdvice、ThrowsAdvice)包装成了拦截器,其中
在执行代理对象时也是调用拦截器,有以下六种拦截器:
- MethodBeforeAdviceInterceptor
- AfterReturningAdviceInterceptor
- ThrowsAdviceInterceptor
以上三个拦截器包装成动态拦截器InterceptorAndDynamicMethodMatcher
返回
class InterceptorAndDynamicMethodMatcher {
final MethodInterceptor interceptor;
final MethodMatcher methodMatcher;
public InterceptorAndDynamicMethodMatcher(MethodInterceptor interceptor, MethodMatcher methodMatcher) {
this.interceptor = interceptor;
this.methodMatcher = methodMatcher;
}
}
构建ReflectiveMethodInvocation
对象,执行proceed()
方法
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
// 如果拦截器已经执行完,执行连接点方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 获取拦截器
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher dm) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
// 动态判断拦截器是否匹配
if (dm.matcher().matches(this.method, targetClass, this.arguments)) {
// 匹配成功,执行拦截器
// 在拦截器的invoke方法中,还会调用ReflectiveMethodInvocation的proceed方法,也就是当前proceed方法
return dm.interceptor().invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
// 匹配失败,跳过当前拦截器,处理下一个
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
执行动态拦截器InterceptorAndDynamicMethodMatcher#matcher()
得到MethodMatcher
,因为目标类有多个方法,所以在执行方法时,判断当前执行的方法是否是切入点,如果是切入点,则执行拦截器的invoke
方法
以MethodBeforeAdviceInterceptor#invoke()
为例子
public Object invoke(MethodInvocation mi) throws Throwable {
// 在目标方法执行前调用AspectJMethodBeforeAdvice#before()方法
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
// 调用ReflectiveMethodInvocation#proceed()方法,会继续执行拦截器链
return mi.proceed();
}
但是AspectJAroundAdvice
比较特殊
public Object invoke(MethodInvocation mi) throws Throwable {
if (!(mi instanceof ProxyMethodInvocation pmi)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
// 获取ProceedingJoinPoint对象
ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
// 获取JoinPointMatch对象,用于匹配切点
JoinPointMatch jpm = getJoinPointMatch(pmi);
// 执行环绕通知的逻辑
// 把ProceedingJoinPoint以参数形式传入通知增强方法
// 需要我们自己在通知增强方法调用ProceedingJoinPoint#proceed方法执行目标方法
return invokeAdviceMethod(pjp, jpm, null, null);
}