Spring是如何实现AOP的Spring是如何实现AOP的

在这里插入图片描述

博主 默语带您 Go to New World.
个人主页—— 默语 的博客👦🏻 优秀内容
《java 面试题大全》
《java 专栏》
《idea技术专区》
《spring boot 技术专区》
《MyBatis从入门到精通》
《23种设计模式》
《经典算法学习》
《spring 学习》
《MYSQL从入门到精通》数据库是开发者必会基础之一~
🍩惟余辈才疏学浅,临摹之作或有不妥之处,还请读者海涵指正。☕🍭
🪁 吾期望此文有资助于尔,即使粗浅难及深广,亦备添少许微薄之助。苟未尽善尽美,敬请批评指正,以资改进。!💻⌨


默语是谁?

大家好,我是 默语,别名默语博主,擅长的技术领域包括Java、运维和人工智能。我的技术背景扎实,涵盖了从后端开发到前端框架的各个方面,特别是在Java 性能优化、多线程编程、算法优化等领域有深厚造诣。

目前,我活跃在CSDN、掘金、阿里云和 51CTO等平台,全网拥有超过10万的粉丝,总阅读量超过1400 万。统一 IP 名称为 默语 或者 默语博主。我是 CSDN 博客专家、阿里云专家博主和掘金博客专家,曾获博客专家、优秀社区主理人等多项荣誉,并在 2023 年度博客之星评选中名列前 50。我还是 Java 高级工程师、自媒体博主,北京城市开发者社区的主理人,拥有丰富的项目开发经验和产品设计能力。希望通过我的分享,帮助大家更好地了解和使用各类技术产品,在不断的学习过程中,可以帮助到更多的人,结交更多的朋友.


我的博客内容涵盖广泛,主要分享技术教程、Bug解决方案、开发工具使用、前沿科技资讯、产品评测与使用体验。我特别关注云服务产品评测、AI 产品对比、开发板性能测试以及技术报告,同时也会提供产品优缺点分析、横向对比,并分享技术沙龙与行业大会的参会体验。我的目标是为读者提供有深度、有实用价值的技术洞察与分析。


AOP:面向切面编程,看起来很高大尚,这里继续上面的Bean的提供,简述下AOP原理

AOP入口

在AbstractAutoProxyCreator中存在以下两个方法,一个是对应循环依赖中如何提前暴露Bean的引用地址,另一个则是根据Bean实例获取最终Bean的后置处理器中,二者都调用了一个方法:wrapIfNecessary,这就是AOP的入口,前者对应开发者在注入单例bean时获取到代理对象(例如Service层注入其他Service得到的是其代理对象),后置则对应普通流程的增强类方法。

// 暴露早期Bean的引用
public Object getEarlyBeanReference(Object bean, String beanName) {
	Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
	// 缓存
	this.earlyProxyReferences.put(cacheKey, bean);
	// 包装
	return this.wrapIfNecessary(bean, beanName, cacheKey);
}

// Bean初始化的后置处理器
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
	if (bean != null) {
		Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
		// 不在缓存中则进行包装
		if (this.earlyProxyReferences.remove(cacheKey) != bean) {
			return this.wrapIfNecessary(bean, beanName, cacheKey);
		}
	}
	return bean;
}

看下该方法

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
   // 注意在postProcessBeforeInstantiation中会将已经创建过代理对象的Bean放入targetSourcedBeans中
   if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
      return bean;
   }
   // 跳过不用代理的类,已处理的或者不需要代理的
   if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
      return bean;
   }
   // 跳过不代理的类,例如:Advice、Pointcut、Advisor、AopInfrastructureBean和.ORIGINAL结尾的Bean
   if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
      this.advisedBeans.put(cacheKey, Boolean.FALSE);
      return bean;
   }

   // 查询该Bean需要代理的通知器列表,存在则代理(这里无指定targetSource)
   Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
   if (specificInterceptors != DO_NOT_PROXY) {
      // 需要增强的Bean,标志True
      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;
}

以上方法的含义是对需要代理的Bean,构建代理对象返回。需要代理的标志是存在specificInterceptors,因此下面如何查找这些特殊的拦截器则是AOP的匹配核心

哪些Bean需要增强
@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();
}

// 获取通知器列表
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
   // 候选增强器列表 
   List<Advisor> candidateAdvisors = findCandidateAdvisors();
   // 从候选中选出可使用的增强器列表
   List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
   // 模板方法,对已筛选后的增强器提供对外扩展功能
   extendAdvisors(eligibleAdvisors);
   if (!eligibleAdvisors.isEmpty()) {
      // 排序  
      eligibleAdvisors = sortAdvisors(eligibleAdvisors);
   }
   return eligibleAdvisors;
}

第一步:获取增强器候选列表:findCandidateAdvisors,其核心代码如下

advisors.add(this.beanFactory.getBean(name, Advisor.class));

从当前IOC容器(递归父容器)中获取所有Advisor的实现类,name为IOC中所有的advisor的实现类名称,这是一个遍历添加操作,name列表会缓存,遍历添加操作不缓存

第二步:筛选匹配当前Bean的增强器列表:findAdvisorsThatCanApply

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
   if (candidateAdvisors.isEmpty()) {
      return candidateAdvisors;
   }
   List<Advisor> eligibleAdvisors = new ArrayList<>();
   // 第一次遍历,查找引介增强 
   for (Advisor candidate : candidateAdvisors) {
      // 类级别的增强器  
      if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
         eligibleAdvisors.add(candidate);
      }
   }
   boolean hasIntroductions = !eligibleAdvisors.isEmpty();
   // 第二次遍历,查找方法增强
   for (Advisor candidate : candidateAdvisors) {
      if (candidate instanceof IntroductionAdvisor) {
         // already processed
         continue;
      }
      if (canApply(candidate, clazz, hasIntroductions)) {
         eligibleAdvisors.add(candidate);
      }
   }
   return eligibleAdvisors;
}

// 是否适用的匹配条件
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
   // 引介增强 
   if (advisor instanceof IntroductionAdvisor) {
      return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
   }
     // 切点增强
   else if (advisor instanceof PointcutAdvisor) {
      PointcutAdvisor pca = (PointcutAdvisor) advisor;
      return canApply(pca.getPointcut(), targetClass, hasIntroductions);
   }
   else {
      // It doesn't have a pointcut so we assume it applies.
      return true;
   }
}

在这里引入了2个概念:IntroductionAdvisor(引介增强)、PointcutAdvisor(切点增强)。通俗而言IntroductionAdvisor就是类层次的增强,给某个类添加新方法什么的,匹配时只匹配类就行。PointcutAdvisor是方法层次的增强,也是最常用的,例如在方法之前、之后、抛出异常时新增功能等。在查找的时候优先查找了IntroductionAdvisor,然后才是PointcutAdvisor。

PointcutAdvisor 有 6 个具体的实现类:

  • DefaultPointcutAdvisor 最常用的切面类型,通过它可以设定任意的 Pointcut 和 Advice 定义一个切面,唯一不支持的是引介的切面类型,可以通过扩展该类实现自定义切面。
  • NameMatchMethodPointcutAdvisor 实现按方法名来定义切点的切面。
  • RegexpMethodPointcutAdvisor 使用Jdk正则表达式来匹配方法名,实现切点定义的切面。
  • StaticMethodMatcherPointcutAdvisor 使用静态方法匹配器来定义切点的切面。默认情况下,匹配所有的目标类。
  • AspecJExpressionPointcutAdvisor 使用 Aspecj 切点表达式来定义切点的切面 。
  • AspecJPointcutAdvisor 使用 AspecJ 语法来定义切点的切面 。

IntroductionAdvisor 接口的2个实现类:

  • DefaultIntroductionAdvisor 默认实现类。
  • DeclareParentsAdvisor 实现使用 AspectJ 语言的 DeclareParent 注解表示的引介切面。

两种增强器都有一个canApply方法在进行匹配,IntroductionAdvisor中存在一个ClassFilter#matches;Pointcut中则使用ClassFilter#matches和MethodMatcher#matches,也就是只要满足matches就会添加到以上的匹配增强器列表中

创建代理

返回最初始的地方,找到了这些specificInterceptors,则开始进行代理

具体流程如下

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,  @Nullable Object[] specificInterceptors, TargetSource targetSource) {

   // ConfigurableListableBeanFactory实例则将该BeanDefinition添加一个属性originalTargetClass,指向beanClass
   // 在由BeanFactory实例化其他Bean时候使用的BeanDefinition 就会有该属性
   if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
      AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
   }

   ProxyFactory proxyFactory = new ProxyFactory();
   // 原型模式,复制属性 
   proxyFactory.copyFrom(this);

   // 判断代理方式采用的是使用类还是接口 (默认false即采用接口)
   if (!proxyFactory.isProxyTargetClass()) {
      // BeanDdefinition指定了preserveTargetClass=true则使用类
      if (shouldProxyTargetClass(beanClass, beanName)) {
         proxyFactory.setProxyTargetClass(true);
      }
     // 未指定则尝试从类及其父类的所有接口列表中过滤掉回调接口(Aware、DisposableBean等容器接口)、内部接口(“groovy.lang.GroovyObject”等)
     // 从过滤后接口列表中找到合适代理的接口找不到则仍然使用类进行代理   
      else {
         evaluateProxyInterfaces(beanClass, proxyFactory);
      }
   }
   // 构建增强器链
   Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
   proxyFactory.addAdvisors(advisors);
   proxyFactory.setTargetSource(targetSource);
   // 模板方法,扩展代理工厂
   customizeProxyFactory(proxyFactory);

   proxyFactory.setFrozen(this.freezeProxy);
   // 优化,如果是已匹配好的则做个标记,后续不在走匹配流程 
   if (advisorsPreFiltered()) {
      proxyFactory.setPreFiltered(true);
   }
   // 代理工厂生产代理对象 
   return proxyFactory.getProxy(getProxyClassLoader());
}

上面这个创建流程实质为构建该Bean的代理工厂ProxyFactory的过程。这里使用原型模式构建一个专属的ProxyFactory实例,然后初步判断该Bean的创建方式,JDK(接口)还是CGLIB(类)

判断完成之后,则构建该类的增强器链,这个增强器链来源于之前查找的增强器列表,这里只是后续处理下,处理完毕后,设置ProxyFactory基本属性,这样ProxyFactory基本构建完成。customizeProxyFactory则是暴露给使用者的接口,用于扩展ProxyFactory功能。然后工厂就开始工作了。

处理流程也看下,最终Advisor的没变,但是Advice全部转为 DefaultPointcutAdvisor,需要注意的是这里添加了2种增强:1. 公共拦截器:commonInterceptors 2. 默认适配器(AdvisorAdapter)中的适配的Advisor

protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
   // 获取公共的拦截器
   Advisor[] commonInterceptors = resolveInterceptorNames();
   List<Object> allInterceptors = new ArrayList<>();
   // 公共的排在前 
   if (specificInterceptors != null) {
      allInterceptors.addAll(Arrays.asList(specificInterceptors));
      if (commonInterceptors.length > 0) {
         if (this.applyCommonInterceptorsFirst) {
            allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
         }
         else {
            allInterceptors.addAll(Arrays.asList(commonInterceptors));
         }
      }
   }
  
   Advisor[] advisors = new Advisor[allInterceptors.size()];
   // 使用适配器包装处理下,实际为DefaultAdvisorAdapterRegistry
   for (int i = 0; i < allInterceptors.size(); i++) {
      advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
   }
   return advisors;
}

代理创建:DefaultAopProxyFactory#createAopProxy

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
   // 代理开启优化配置或者支持类方式代理或者不直接接口代理 
   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.");
      }
      // 如果目标类是接口或者就是一个代理类则使用JDK动态代理  
      if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
         return new JdkDynamicAopProxy(config);
      }
      // 其他使CGLIB动态代理
      return new ObjenesisCglibAopProxy(config);
   }
   // 其他默认使用JDK代理
   else {
      return new JdkDynamicAopProxy(config);
   }
}

这里使用了JDK或者CGLIB代理,默认为JDK代理,如果目标类targetClass是接口或者是JDK代理类则直接使用JDK代理。JDK代理的核心是invoke,CGLIB代理的核心是callBack,这是Spring针对增强器进行了处理

JdkDynamicAopProxy的invoke流程,这里是说明核心代码


@Override
@Nullable
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.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) {
         // There is only getDecoratedClass() declared -> dispatch to proxy config.
         return AopProxyUtils.ultimateTargetClass(this.advised);
      }
      //  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;
      if (this.advised.exposeProxy) {
         // 上下文代理对象的处理,设置的是当前对象
         oldProxy = AopContext.setCurrentProxy(proxy);
         setProxyContext = true;
      }
      target = targetSource.getTarget();
      Class<?> targetClass = (target != null ? target.getClass() : null);

      // 获取该方法的拦截器链
      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

      //不存在增强器,则直接反射调用
      if (chain.isEmpty()) {
         Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
         retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
      }
      else {
         // 构建一个方法调用对象MethodInvocation
         MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
         // 开始调用
         retVal = invocation.proceed();
      }

      // 返回结果校验
      Class<?> returnType = method.getReturnType();
      if (retVal != null && retVal == target &&
            returnType != Object.class && returnType.isInstance(proxy) &&
            !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
         // 返回this
         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) {
         // 重置旧的代理对象.
         AopContext.setCurrentProxy(oldProxy);
      }
   }
}

ObjenesisCglibAopProxy的调用流程,只展示核心调用流程intercept


@Override
@Nullable
public 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;
      }
      target = targetSource.getTarget();
      Class<?> targetClass = (target != null ? target.getClass() : null);
      // 获取增强器链
      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
      Object retVal;
     // 无增强器的处理,直接反射
      if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
         Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
         retVal = methodProxy.invoke(target, argsToUse);
      }
      else {
         // 构建CglibMethodInvocation并调用,
         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);
      }
   }
}

二者真是实现AOP的地方在于增强链的调用

AOP本质

构建一个增强器链,在被代理对象方法调用时按照情况进行调用

增强链的构建:getInterceptorsAndDynamicInterceptionAdvice—>DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice

@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
      Advised config, Method method, @Nullable Class<?> targetClass) {

   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) {
      // 切入点增强器  
      if (advisor instanceof PointcutAdvisor) {
         PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
         // 类级别匹配
         if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
            // 方法匹配
            MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
            boolean match;
            if (mm instanceof IntroductionAwareMethodMatcher) {
               if (hasIntroductions == null) {
                  hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
               }
               match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
            }
            else {
               match = mm.matches(method, actualClass);
            }
            // 完全匹配
            if (match) {
               // 从注册表中获取方法拦截器 
               MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
               // 匹配器是动态匹配,含占位符 ,则在包装一层,待后续处理
               if (mm.isRuntime()) {
                  for (MethodInterceptor interceptor : interceptors) {
                     interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                  }
               }
               // 不是则直接添加
               else {
                  interceptorList.addAll(Arrays.asList(interceptors));
               }
            }
         }
      }
      // 引介增强,匹配类即可
      else if (advisor instanceof IntroductionAdvisor) {
         IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
         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;
}

增强链的调用

// 伪责任链调用
@Nullable
public Object proceed() throws Throwable {
    // 最后一个调用后直接返回
	if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
		// jdk反射调用
		return this.invokeJoinpoint();
	} else {
	    // 逐个调用 ++i
		Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;
			Class<?> targetClass = this.targetClass != null ? this.targetClass : this.method.getDeclaringClass();
			return dm.methodMatcher.matches(this.method, targetClass, this.arguments) ? dm.interceptor.invoke(this) : this.proceed();
		} else {
			return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
		}
	}
}

看到这一步就明白AOP到底是什么原理了,只是Spring设计的很巧妙,各种封装眼花缭乱,涉及到字节码的就不多说了,明白到这一步足够了

在这里插入图片描述


🪁🍁 希望本文能够给您带来一定的帮助🌸文章粗浅,敬请批评指正!🍁🐥

如对本文内容有任何疑问、建议或意见,请联系作者,作者将尽力回复并改进📓;(联系微信:Solitudemind )

点击下方名片,加入IT技术核心学习团队。一起探索科技的未来,共同成长。

在这里插入图片描述

更多推荐