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.mzph.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 原生支持流量按比例分配功能,无需复杂编码即可实现灰度验证。本文将详细解析其实现方法、最佳…