SpringBoot AOP 源碼解析

文章目錄

  • 一、AOP 代碼示例
    • 1. 準備注解和目標類
    • 2. 定義 Aspect
    • 3. 結論
  • 二、源碼
    • 1. AOP 實現核心類
    • 2. 代理類的創建流程
      • 2.1 核心類 AbstractAutoProxyCreator
      • 2.2 AbstractAutoProxyCreator#postProcessBeforeInstantiation
      • 2.3 AspectJAwareAdvisorAutoProxyCreator#shouldSkip
      • 2.4 aspectJAdvisorsBuilder#buildAspectJAdvisors
      • 2.5 advisorFactory#getAdvisors
      • 2.6 AbstractAutoProxyCreator#postProcessAfterInitialization
      • 2.7 AbstractAutoProxyCreator#wrapIfNecessary
      • 2.8 添加 ExposeInvocationInterceptor
      • 2.9 創建代理對象 createProxy()
      • 2.10 ProxyFactory#getProxy
      • 2.11 CGLIB 代理類
      • 2.12 獲取攔截器 getCallbacks
    • 3. Aop自動配置
      • 3.1 `AopAutoConfiguration` 源碼
      • 3.2 `@EnableAspectJAutoProxy`
      • 3.3 AspectJAutoProxyRegistrar
      • 3.4 注冊
    • 4. AOP 執行流程
      • 4.1 攔截器 DynamicAdvisedInterceptor
      • 4.2 方法執行 proceed
    • 總結
      • ExposeInvocationInterceptor


一、AOP 代碼示例

1. 準備注解和目標類

/*** @author zhuRuiBo* @date 2025/2/21 11:22*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {String value() default "";
}@Slf4j
@RestController
@RequestMapping("/aop")
public class AopDemoController {/*** 切點*/@Log("s1LogAnno")@GetMapping("s1")public String s1() {log.info("s1 ---");return "ok";}
}

2. 定義 Aspect

定義兩個 Aspect, 一個 Around Aspect, 一個是分離(Before, After, AfterReturn, AfterThrowing)的 Aspect

/*** around Aspect* @author zhuRuiBo* @date 2025/2/21 11:25*/
@Slf4j
@Component
@Aspect
public class LogAroundAspect {@Pointcut("@annotation(com.zrb.aop.demo.Log)")public void pointcut(){}@Around("pointcut()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {log.info("around - before: {}", joinPoint.getSignature().getName());Object result = joinPoint.proceed();log.info("around - after: {}", joinPoint.getSignature().getName());return result;}
}
@Slf4j
@Component
@Aspect
public class LogSeparateAspect {@Pointcut("@annotation(com.zrb.aop.demo.Log)")public void pointcut(){}@Before("pointcut()")public void before(){log.info("LogSeparateAspect before");}@After("pointcut()")public void after() {log.info("LogSeparateAspect after");}@AfterReturning("pointcut()")public void afterReturning() {log.info("LogSeparateAspect afterReturning");}@AfterThrowing("pointcut()")public void afterThrowing() {log.info("LogSeparateAspect afterThrowing");}
}

3. 結論

2025-02-26 14:12:39.843  INFO 67047 --- [io-10010-exec-1] com.zrb.aop.demo.LogAroundAspect         : around - before: s1
2025-02-26 14:12:39.843  INFO 67047 --- [io-10010-exec-1] com.zrb.aop.demo.LogSeparateAspect       : LogSeparateAspect before
2025-02-26 14:12:39.850  INFO 67047 --- [io-10010-exec-1] com.zrb.aop.demo.AopDemoController       : s1 ---
2025-02-26 14:12:39.850  INFO 67047 --- [io-10010-exec-1] com.zrb.aop.demo.LogSeparateAspect       : LogSeparateAspect afterReturning
2025-02-26 14:12:39.850  INFO 67047 --- [io-10010-exec-1] com.zrb.aop.demo.LogSeparateAspect       : LogSeparateAspect after
2025-02-26 14:12:39.850  INFO 67047 --- [io-10010-exec-1] com.zrb.aop.demo.LogAroundAspect         : around - after: s1

二、源碼

此處源碼參考 springboot-2.7.3 版本
本篇源碼只解析 Aop 的核心, 直接跳過 spring 的生命周期流程

1. AOP 實現核心類

  1. AbstractAutoProxyCreator: 創建代理的核心類, 代理對象就在 wrapIfNecessary 方法中創建
  2. @EnableAspectJAutoProxy 開啟 Aspect 自動配置,或許在老版本中我們還需要手動添加這個注解, 但是在 2.7.3 版本中,已經不需要手動引入這個注解了
  3. AopAutoConfiguration : Aop 自動配置類
  4. AdvisorAdvice:Advisor 中包含了一個 Advice, 而每一個 Aop 注解(@Around,@Before, @After 等等)都會被包裝成為一個 Advice, 最終也是通過 Advice 去執行目標方法

2. 代理類的創建流程

2.1 核心類 AbstractAutoProxyCreator

/*** 實現了 SmartInstantiationAwareBeanPostProcessor, 所以在 Bean 的生命周期中會執行該類的* postProcessBeforeInstantiation 和 postProcessAfterInstantiation* 這里直接說結論: 代理一般是在 postProcessAfterInstantiation 中創建的* 	postProcessBeforeInstantiation 中也可能會創建,但是一般不會在這個方法中創建* 擴展:SmartInstantiationAwareBeanPostProcessor 本身還有一個 getEarlyBeanReference 的方法, 這個方法被三級緩存所引用* 目的是為了方便隨時從三級緩存中創建代理,因此代理對象也可能在三級緩存中直接創建*/
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupportimplements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware

2.2 AbstractAutoProxyCreator#postProcessBeforeInstantiation

@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {Object cacheKey = getCacheKey(beanClass, beanName);if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {if (this.advisedBeans.containsKey(cacheKey)) {return null;}// 注意這個 shouldSkip 及其重要,實現類 AspectJAwareAdvisorAutoProxyCreator 里面會創建 Advisor// 然后 Advisor 構造器中會創建 Adviceif (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return null;}}// 一般來講這個地方獲取到的是 null, 因此一般不會在這個地方就創建代理類TargetSource targetSource = getCustomTargetSource(beanClass, beanName);if (targetSource != null) {if (StringUtils.hasLength(beanName)) {this.targetSourcedBeans.add(beanName);}Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);// 創建代理類Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}return null;
}

2.3 AspectJAwareAdvisorAutoProxyCreator#shouldSkip

@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {// TODO: Consider optimization by caching the list of the aspect names// 獲取 ioc 中手動注入的 Advisor, 在 AnnotationAwareAspectJAutoProxyCreator 中會創建 Aspect 中的 Advisor// 至于為什么會是 AnnotationAwareAspectJAutoProxyCreator 可以參考第二章List<Advisor> candidateAdvisors = findCandidateAdvisors();for (Advisor advisor : candidateAdvisors) {if (advisor instanceof AspectJPointcutAdvisor &&((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {return true;}}return super.shouldSkip(beanClass, beanName);
}/*** AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors*/
@Override
protected List<Advisor> findCandidateAdvisors() {// Add all the Spring advisors found according to superclass rules.// super.findCandidateAdvisors() 是獲取 spring 中顯示加入的 AdvisorList<Advisor> advisors = super.findCandidateAdvisors();// Build Advisors for all AspectJ aspects in the bean factory.if (this.aspectJAdvisorsBuilder != null) {// buildAspectJAdvisors() 將 Aspect 類,構建成 Advisoradvisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());}return advisors;
}

2.4 aspectJAdvisorsBuilder#buildAspectJAdvisors

將 Aspect 構建成 Advisor

public List<Advisor> buildAspectJAdvisors() {List<String> aspectNames = this.aspectBeanNames;if (aspectNames == null) {synchronized (this) {aspectNames = this.aspectBeanNames;// 只會初始化一次if (aspectNames == null) {List<Advisor> advisors = new ArrayList<>();aspectNames = new ArrayList<>();// 獲取所有的 beanNamesString[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);for (String beanName : beanNames) {// 判斷是否符合條件的 beanName, 當前一直返回 trueif (!isEligibleBean(beanName)) {continue;}// We must be careful not to instantiate beans eagerly as in this case they// would be cached by the Spring container but would not have been weaved.Class<?> beanType = this.beanFactory.getType(beanName, false);if (beanType == null) {continue;}// 判斷當前 bean 是否是一個 Aspect// 很簡單,通過判斷該類上是否注有 @Aspect 注解if (this.advisorFactory.isAspect(beanType)) {aspectNames.add(beanName);AspectMetadata amd = new AspectMetadata(beanType, beanName);if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {MetadataAwareAspectInstanceFactory factory =new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);// 通過 advisorFactory 創建 advisorList<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);if (this.beanFactory.isSingleton(beanName)) {this.advisorsCache.put(beanName, classAdvisors);}else {this.aspectFactoryCache.put(beanName, factory);}advisors.addAll(classAdvisors);}...}}this.aspectBeanNames = aspectNames;return advisors;}}}...return advisors;
}

2.5 advisorFactory#getAdvisors

/*** advisorFactory#getAdvisors*/
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();validate(aspectClass);...MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);List<Advisor> advisors = new ArrayList<>();// getAdvisorMethods 是獲取了除了 @Pointcut 之外的所有的方法for (Method method : getAdvisorMethods(aspectClass)) {...// getAdvisor 中,如果沒有任何的注解將會返回 null// 默認 Advisor 實現類為 InstantiationModelAwarePointcutAdvisorImpl, 構造器中會創建 AdviseAdvisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);if (advisor != null) {advisors.add(advisor);}}...return advisors;
}/*** getAdvisor()*/
@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,int declarationOrderInAspect, String aspectName) {validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());AspectJExpressionPointcut expressionPointcut = getPointcut(candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());if (expressionPointcut == null) {return null;}// 默認的 Advisor 實現類為 InstantiationModelAwarePointcutAdvisorImplreturn new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

2.6 AbstractAutoProxyCreator#postProcessAfterInitialization

// AbstractAutoProxyCreator#postProcessAfterInitialization
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {Object cacheKey = getCacheKey(bean.getClass(), beanName);if (this.earlyProxyReferences.remove(cacheKey) != bean) {// 核心方法 wrapIfNecessary// 另外三級緩存中存放的 lambda 也會調用這個方法 return wrapIfNecessary(bean, beanName, cacheKey);}}return bean;
}

2.7 AbstractAutoProxyCreator#wrapIfNecessary

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. // 創建代理對象,如果我們有 Advice 的話// 獲取所有的 Advisor, 如果存在 Advisor 就要創建代理對象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;
}

2.8 添加 ExposeInvocationInterceptor

@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);if (advisors.isEmpty()) {return DO_NOT_PROXY;}return advisors.toArray();
}/*** AbstractAdvisorAutoProxyCreator#findEligibleAdvisors*/
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {// 獲取所有的 AdvisorList<Advisor> candidateAdvisors = findCandidateAdvisors();List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);// 添加一個頭部的 Advisor: extendAdvisors(eligibleAdvisors);if (!eligibleAdvisors.isEmpty()) {eligibleAdvisors = sortAdvisors(eligibleAdvisors);}return eligibleAdvisors;
}/* * AspectJAwareAdvisorAutoProxyCreator#extendAdvisors*/
@Override
protected void extendAdvisors(List<Advisor> candidateAdvisors) {AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}/*** AspectJProxyUtils#makeAdvisorChainAspectJCapableIfNecessary*/
public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {// Don't add advisors to an empty list; may indicate that proxying is just not requiredif (!advisors.isEmpty()) {// 在 Advisor 上添加一個 ExposeInvocationInterceptor.ADVISORif (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {advisors.add(0, ExposeInvocationInterceptor.ADVISOR);return true;}}return false;
}

2.9 創建代理對象 createProxy()

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,@Nullable Object[] specificInterceptors, TargetSource targetSource) {if (this.beanFactory instanceof ConfigurableListableBeanFactory) {AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);}// 將需要創建的配置信息保存到 proxyFactory,proxyFactory 創建代理的時候定制化ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.copyFrom(this);...// 獲取 AdvisorsAdvisor[] advisors = buildAdvisors(beanName, specificInterceptors);proxyFactory.addAdvisors(advisors);proxyFactory.setTargetSource(targetSource);// 鉤子, 可以定制化 proxyFactorycustomizeProxyFactory(proxyFactory);...// 通過 proxyFactory 獲取代理對象return proxyFactory.getProxy(classLoader);
}

2.10 ProxyFactory#getProxy

/*** ProxyFactory#getProxy*/
public Object getProxy(@Nullable ClassLoader classLoader) {return createAopProxy().getProxy(classLoader);
}/*** createAopProxy*/
protected final synchronized AopProxy createAopProxy() {if (!this.active) {activate();}return getAopProxyFactory().createAopProxy(this);
}/*** createAopProxy()* 總結:* 1. 如果沒有開啟“類”類型的代理, 直接使用 JDK 的代理* 2. 如果目標類是一個接口, 一個已經被代理過的類, 或者是一個 lambda 表達式, 都是用 JDK 的代理, 否則是用 CGLIB*/@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {...// 這個判斷, 簡單來說就是開啟了類類型的代理, 如果沒有開啟, 直接使用 JDK 的代理if (!NativeDetector.inNativeImage() &&(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {// 如果目標類是一個接口, 一個已經被代理過的類, 或者是一個 lambda 表達式, 都是用 JDK 的代理, 否則是用 CGLIBif (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {return new JdkDynamicAopProxy(config);}return new ObjenesisCglibAopProxy(config);}else {return new JdkDynamicAopProxy(config);}
}

2.11 CGLIB 代理類

下面的代碼, 需要知道 CGLIB 如何使用

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {try {... // Configure CGLIB Enhancer...// 創建 EnhancerEnhancer enhancer = createEnhancer();...// 獲取 callbackCallback[] callbacks = getCallbacks(rootClass);...// 將 callback 設置到 enhancer 上return createProxyClassAndInstance(enhancer, callbacks);}...
}

2.12 獲取攔截器 getCallbacks

private Callback[] getCallbacks(Class<?> rootClass) throws Exception {...// Choose an "aop" interceptor (used for AOP calls).// Aop 的默認 CallbackCallback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);...return callbacks;
}

3. Aop自動配置

查看 Springboot 的自動配置類中與 Aop 相關的, 可以看到 springboot 引入了一個 AopAutoConfiguration
在這里插入圖片描述

3.1 AopAutoConfiguration 源碼

	/*** spring.aop.proxy-target-class 指的是是否自動代理“類”類型的* 可以看到無論如何都會引入 @EnableAspectJAutoProxy*/@AutoConfiguration@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)public class AopAutoConfiguration {@Configuration(proxyBeanMethods = false)@ConditionalOnClass(Advice.class)static class AspectJAutoProxyingConfiguration {@Configuration(proxyBeanMethods = false)@EnableAspectJAutoProxy(proxyTargetClass = false)@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false")static class JdkDynamicAutoProxyConfiguration {}@Configuration(proxyBeanMethods = false)@EnableAspectJAutoProxy(proxyTargetClass = true)@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",matchIfMissing = true)static class CglibAutoProxyConfiguration {}}...}

3.2 @EnableAspectJAutoProxy

/*** 引入了一個 AspectJAutoProxyRegistrar 類*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {boolean proxyTargetClass() default false;boolean exposeProxy() default false;}

3.3 AspectJAutoProxyRegistrar

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {/*** 注冊 Aop 需要的類*/@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {// 注冊 AbstractAutoProxyCreator 的具體子類AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);AnnotationAttributes enableAspectJAutoProxy =AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);if (enableAspectJAutoProxy != null) {if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);}if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);}}}}

3.4 注冊

@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}/*** 由此可見 @EnableAspectJAutoProxy 注冊的 AbstractAutoProxyCreator 為 AnnotationAwareAspectJAutoProxyCreator*/
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

4. AOP 執行流程

這里只研究 CGLIB 的代理

4.1 攔截器 DynamicAdvisedInterceptor

從源碼 1 可知,代理類的攔截器是 DynamicAdvisedInterceptor,當執行目標方法的時候會執行到該類的 interceptor 方法中

@Override
@Nullablepublic Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {Object oldProxy = null;boolean setProxyContext = false;Object target = null;TargetSource targetSource = this.advised.getTargetSource();try {if (this.advised.exposeProxy) {// Make invocation available if necessary.oldProxy = AopContext.setCurrentProxy(proxy);setProxyContext = true;}// 這行代碼也很重要, advised 就是之前的 ProxyFactory, 這里面將每個 Advisor 里面的 Advise 取出來組成一個鏈// 第一個 Advise 是 ExposeInvocationInterceptor#ADVISORList<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);Object retVal;// Check whether we only have one InvokerInterceptor: that is,// no real advice, but just reflective invocation of the target.if (chain.isEmpty() && CglibMethodInvocation.isMethodProxyCompatible(method)) {...}else {// We need to create a method invocation...// 創建一個 CglibMethodInvocation, 執行目標方法// CglibMethodInvocation 是貫穿整個 aop 上下文的一個對象retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();}retVal = processReturnType(proxy, target, method, retVal);return retVal;}finally {if (target != null && !targetSource.isStatic()) {targetSource.releaseTarget(target);}if (setProxyContext) {// Restore old proxy.AopContext.setCurrentProxy(oldProxy);}}}

4.2 方法執行 proceed

是一個鏈式的執行方式,與 SpringSecurity 的過濾器鏈一樣

@Override
@Nullable
public Object proceed() throws Throwable {// We start with an index of -1 and increment early.if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {// 開始執行目標方法return invokeJoinpoint();}// 找到當前的 AdviceObject interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {// Evaluate dynamic method matcher here: static part will already have// been evaluated and found to match.InterceptorAndDynamicMethodMatcher dm =(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {// dm.interceptor 其實就是各個 Advise// 比如說 @Around 就是 AspectJAroundAdvice, @Before 就是 MethodBeforeAdviceInterceptor// 這里把自身傳遞下去, interceptor執行 proceed() 就會回到當前方法, 當所有的 Advice 執行完成之后, 就會執行目標方法, 然后將返回值依次返回給 Advisereturn 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);}
}

總結

ExposeInvocationInterceptor

它的主要作用是將當前的 MethodInvocation 對象暴露給后續的攔截器或切面,以便在 AOP 鏈中的任何地方都可以訪問當前的調用上下文。在自定義攔截器中,可以通過 ExposeInvocationInterceptor.currentInvocation() 獲取當前的 MethodInvocation

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/72079.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/72079.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/72079.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux:Shell環境變量與命令行參數

目錄 Shell的變量功能 什么是變量 變數的可變性與方便性 影響bash環境操作的變量 腳本程序設計&#xff08;shell script&#xff09;的好幫手 變量的使用&#xff1a;echo 變量的使用&#xff1a;HOME 環境變量相關命令 獲取環境變量 環境變量和本地變量 命令行…

MySQL數據庫入門到大蛇尚硅谷宋紅康老師筆記 高級篇 part 5

第05章_存儲引擎 為了管理方便&#xff0c;人們把連接管理、查詢緩存、語法解析、查詢優化這些并不涉及真實數據存儲的功能劃分為MySQLserver的功能&#xff0c;把真實存取數據的功能劃分為存儲引擎的功能。所t以在MySQLserver完成了查詢優化后&#xff0c;只需按照生成的執行…

JAVA面試_進階部分_23種設計模式總結

1. 單例模式&#xff1a;確保某一個類只有一個實例&#xff0c;而且自行實例化并向整個系統提供這 個實例。 &#xff08;1&#xff09;懶漢式 public class Singleton { /* 持有私有靜態實例&#xff0c;防止被引用&#xff0c;此處賦值為null&#xff0c;目的是實現延遲加載…

滲透測試(WAF過濾information_schema庫的繞過,sqllib-46關,海洋cms9版本的注入)

1.sqlin-lib 46關 打開網站配置文件發現 此網站的對ID進行了排序&#xff0c;我們可以知道&#xff0c;order by接不了union &#xff0c;那我們可以通過測試sort&#xff0c;rond等函數&#xff0c;觀察網頁的反饋來判斷我們的盲注是否正確 我們發現 當參數有sort來排序時&…

AORO M6北斗短報文終端:將“太空黑科技”轉化為安全保障

在衛星導航領域&#xff0c;北斗系統作為我國自主研發的全球衛星導航系統&#xff0c;正以其獨特的短報文通信功能引發全球范圍內的廣泛關注。這一突破性技術不僅使北斗系統在全球四大導航系統中獨樹一幟&#xff0c;具備了雙向通信能力&#xff0c;更通過遨游通訊推出的AORO M…

ARCGIS國土超級工具集1.4更新說明

ARCGIS國土超級工具集V1.4版本&#xff0c;功能已增加至54 個。本次更新在V1.3版本的基礎上&#xff0c;新增了“拓撲問題修復工具”并同時調整了數據處理工具欄的布局、工具操作界面的選擇圖層下拉框新增可選擇位于圖層組內的要素圖層功能、數據保存路徑新增了可選擇數據庫內的…

Element Plus中el-select選擇器的下拉選項列表的樣式設置

el-select選擇器&#xff0c;默認樣式效果&#xff1a; 通過 * { margin: 0; padding: 0; } 去掉內外邊距后的樣式效果&#xff08;樣式變丑了&#xff09;&#xff1a; 通過 popper-class 自定義類名修改下拉選項列表樣式 el-select 標簽設置 popper-class"custom-se…

基于Linux系統的物聯網智能終端

背景 產品研發和項目研發有什么區別&#xff1f;一個令人發指的問題&#xff0c;剛開始工作時項目開發居多&#xff0c;認為項目開發和產品開發區別不大&#xff0c;待后來隨著自身能力的提升&#xff0c;逐步感到要開發一個好產品還是比較難的&#xff0c;我認為項目開發的目的…

java excel xlsx 增加數據驗證

隱藏表下拉框 // 創建隱藏工作表存儲下拉框數據String hiddenSheetName "HiddenSheet"System.currentTimeMillis();Sheet hiddenSheet workbook.createSheet(hiddenSheetName);//設置隱藏sheetworkbook.setSheetHidden(workbook.getSheetIndex(hiddenSheetName), …

linux中安裝部署Jenkins,成功構建springboot項目詳細教程

參考別人配置Jenkins的git地址為https&#xff0c;無法連上github拉取項目&#xff0c;所以本章節介紹通過配置SSH地址來連github拉取項目 目錄&#xff1a; 1、springboot項目 1.1 創建名為springcloudproject的springboot項目工程 1.2 已將工程上傳到github中&#xff0c;g…

提升數據洞察力:五款報表軟件助力企業智能決策

概述 隨著數據量的激增和企業對決策支持需求的提升&#xff0c;報表軟件已經成為現代企業管理中不可或缺的工具。這些軟件能夠幫助企業高效處理數據、生成報告&#xff0c;并將數據可視化&#xff0c;從而推動更智能的決策過程。 1. 山海鯨報表 概述&#xff1a; 山海鯨報表…

MySQL中replace函數用法

語法&#xff1a;replace(field,search,replace) 說明&#xff1a;field - 數據庫表的列名 search - 需要替換的字符串 replace - 替換成的字符串 語義&#xff1a;將列名&#xff1a;field 中出現的search字符串&#xff0c;全部替換成replace字符串。 例子&#xff1a; …

Wireshark Lua 插件教程

本?主要介紹 Lua 腳本在 Wireshark 中的應?, Lua 腳本可以在 Wireshark 中完成如下功能: 從?絡包中提取數據, 或者統計?些數據包(Dumper) 需要解析?種 Wireshark 不提供原??持的協議(Dissector) ?例 協議解析 VREP 協議是 NOGD 框架對于 TRIP 協議的?種延伸和擴展…

吐血整理:在 Docker 中運行 Milvus

直接用docker 錯誤命令&#xff08;這個我試了三遍&#xff0c;浪費了很多時間&#xff09;&#xff1a; docker run -d --name milvus -p 19530:19530 -p 9091:9091 -v /var/lib/milvus:/var/lib/milvus milvusdb/milvus:latest 先看報錯&#xff1a; 2025-02-24 16:02:39 …

【uniapp】在UniApp中實現持久化存儲:安卓--生成寫入數據為jsontxt

在移動應用開發中&#xff0c;數據存儲是一個至關重要的環節。對于使用UniApp開發的Android應用來說&#xff0c;緩存&#xff08;Cache&#xff09;是一種常見的數據存儲方式&#xff0c;它能夠提高應用的性能和用戶體驗。然而&#xff0c;緩存數據在用戶清除緩存或清除應用數…

【Excel】 Power Query抓取多頁數據導入到Excel

抓取多頁數據想必大多數人都會&#xff0c;只要會點編程技項的人都不會是難事兒。那么&#xff0c;如果只是單純的利用Excel軟件&#xff0c;我還真的沒弄過。昨天&#xff0c;我就因為這個在網上找了好久發好久。 1、在數據-》新建查詢-》從其他源-》自網站 &#xff0c;如圖 …

星環科技推出DeepSeek全場景解決方案:即開即用、企業級部署、端側智能三位一體

星環科技&#xff08;688031.SH&#xff09;正式發布DeepSeek全場景解決方案&#xff0c;全面覆蓋個人用戶、企業客戶及行業場景需求&#xff0c;為用戶提供從個人到企業、從云端到本地的全方位AI應用支持&#xff0c;為不同需求的用戶提供了靈活、高效且安全的AI解決方案。 省…

let、const【ES6】

?“我唯一知道的就是我一無所知。” - 蘇格拉底 目錄 塊級作用域&#xff1a;var、let、const的對比&#xff1a;Object.freeze()&#xff1a; 塊級作用域&#xff1a; 塊級作用域指由 {} 包圍的代碼塊&#xff08;如 if、for、while、單獨代碼塊等&#xff09;形成的獨立作用…

C++ 常見面試知識點

主要介紹C常見面試題 1、說一下你理解的C中的四種智能指針 常用接口 T* get(); T& operator*(); T* operator->(); T& operator(const T& val); T* release(); 將 封裝在內部的指針置為nullptr, 但并不會破壞指針所指向的內容, 函 數返回的是內部指針置空之前…

AWS API Gateway灰度驗證實現

在微服務架構中,灰度發布(金絲雀發布)是驗證新版本穩定性的核心手段。通過將小部分流量(如 10%)導向新版本服務,可以在不影響整體系統的情況下快速發現問題。AWS API Gateway 原生支持流量按比例分配功能,無需復雜編碼即可實現灰度驗證。本文將詳細解析其實現方法、最佳…