spring源码分析之AOP开启注解

AOP开启注解

在使用注解@Aspect来进行AOP操作时,需要在xml中进行配置

<!-- 使@Aspect注解生效 -->
<aop:aspectj-autoproxy/>

创建BeanFactory时obtainFreshBeanFactory()在解析xml加载BeanDefinition中,执行parseBeanDefinitions方法进行解析发现其内有逻辑是

delegate.parseCustomElement(ele)

即进行自定义标签的解析,会去META-INF/spring.handlers中寻找对应的handler,该标签的namespace是http://www.springframework.org/schema/aop,去spring.handlers中找到对应的记录

NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler

还有一个配置是spring.schemas,以找到对应的xsd文件

http\://www.springframework.org/schema/aop/spring-aop-3.1.xsd=org/springframework/aop/config/spring-aop-3.1.xsd

然后执行该handler中的init方法

NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
namespaceHandler.init();

即执行AopNamespaceHandler#init

AopNamespaceHandler#init

public void init() {
   // In 2.0 XSD as well as in 2.5+ XSDs
   registerBeanDefinitionParser("config"new ConfigBeanDefinitionParser());
   registerBeanDefinitionParser("aspectj-autoproxy"new AspectJAutoProxyBeanDefinitionParser());
   registerBeanDefinitionDecorator("scoped-proxy"new ScopedProxyBeanDefinitionDecorator());

   // Only in 2.0 XSD: moved to context namespace in 2.5+
   registerBeanDefinitionParser("spring-configured"new SpringConfiguredBeanDefinitionParser());
}

这里可以看到aspectj-autoproxy,也就是说在配置文件中如果存在<aop:aspectj-autoproxy/>就会使用AspectJAutoProxyBeanDefinitionParser进行解析,调用parse方法

class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {

   @Override
   public BeanDefinition parse(Element element, ParserContext parserContext) {
     // 注册AnnotationAwareAspectJAutoProxyCreator
     // AUTO_PROXY_CREATOR_BEAN_NAME ="org.springframework.aop.config.internalAutoProxyCreator"
     // 如果标签中有"proxy-target-class"属性会进行下一步的解析
      AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
     // 对于注解中子节点的处理
      extendBeanDefinition(element, parserContext);
      return null;
   }

   private void extendBeanDefinition(Element element, ParserContext parserContext) {
      BeanDefinition beanDef =
            parserContext.getRegistry().getBeanDefinition(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
      if (element.hasChildNodes()) {
         addIncludePatterns(element, parserContext, beanDef);
      }
   }

   private void addIncludePatterns(Element element, ParserContext parserContext, BeanDefinition beanDef) {
      ManagedList<TypedStringValue> includePatterns = new ManagedList<TypedStringValue>();
      NodeList childNodes = element.getChildNodes();
      for (int i = 0; i < childNodes.getLength(); i++) {
         Node node = childNodes.item(i);
         if (node instanceof Element) {
            Element includeElement = (Element) node;
            TypedStringValue valueHolder = new TypedStringValue(includeElement.getAttribute("name"));
            valueHolder.setSource(parserContext.extractSource(includeElement));
            includePatterns.add(valueHolder);
         }
      }
      if (!includePatterns.isEmpty()) {
         includePatterns.setSource(parserContext.extractSource(element));
         beanDef.getPropertyValues().add("includePatterns", includePatterns);
      }
   }

}

而在registerBeanPostProcessors(beanFactory)中会去进行注册BeanPostProcessor,在上面解析xml注册的AnnotationAwareAspectJAutoProxyCreator的结构还挺复杂,实现的重要的两个接口都标出来了,实现了BeanPostProcessor和BeanFactoryAware两个接口

AOP解析
AOP解析

在该registerBeanPostProcessors(beanFactory)方法中会找到beanFactory中所有BeanPostProcessor的类,然后获取到该类实例

String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.classtruefalse);
// 注册AnnotationAwareAspectJAutoProxyCreator时的beanName为org.springframework.aop.config.internalAutoProxyCreator
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);

在获取bean的时候会创建bean,但是不要忘了该类还实现了一个BeanFactoryAware接口,在创建bean之后会进行初始化,也就会执行org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeAwareMethods方法

if (bean instanceof BeanFactoryAware) {
   ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}

这样就会执行AbstractAdvisorAutoProxyCreator#setBeanFactory,也没干什么事,就是给几个变量赋了个值

// org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#setBeanFactory
@Override
public void setBeanFactory(BeanFactory beanFactory) {
   super.setBeanFactory(beanFactory);
   if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
      throw new IllegalArgumentException(
            "AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
   }
   initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
}

// org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#initBeanFactory
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
  // advisorRetrievalHelper赋值 BeanFactoryAdvisorRetrievalHelperAdapter实例化
  super.initBeanFactory(beanFactory);
  if (this.aspectJAdvisorFactory == null) {
   this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
  }
  this.aspectJAdvisorsBuilder =
    new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
 }

进行处理

由于实现了BeanPostProcessor接口,在进行实例化bean的前后会调用该类的postProcessBeforeInitialization和postProcessAfterInitialization

这里AnnotationAwareAspectJAutoProxyCreator是继承的AbstractAutoProxyCreator类

// # AbstractAutoProxyCreator
@Override
 public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
  Object cacheKey = getCacheKey(beanClass, beanName);

  if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
   if (this.advisedBeans.containsKey(cacheKey)) {
    return null;
   }
      // shouldSkip获取切面信息加入到缓存中
   if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return null;
   }
  }

  // Create proxy here if we have a custom TargetSource.
  // Suppresses unnecessary default instantiation of the target bean:
  // The TargetSource will handle target instances in a custom fashion.
  if (beanName != null) {
   TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
   if (targetSource != null) {
    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;
 }


@Override
 public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  if (bean != null) {
      // 根据给定的bean的class和name生成一个key
   Object cacheKey = getCacheKey(bean.getClass(), beanName);
   if (this.earlyProxyReferences.remove(cacheKey) != bean) {
        // 进行代理
    return wrapIfNecessary(bean, beanName, cacheKey);
   }
  }
  return bean;
 }

在创建bean的过程中调用了org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation来进行调用BeanPostProcessor接口

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
   Object bean = null;
   if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
      // Make sure bean class is actually resolved at this point.
      if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
         Class<?> targetType = determineTargetType(beanName, mbd);
         if (targetType != null) {
           // 前置处理 调用BeanPostProcessor#postProcessBeforeInstantiation
            bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
            if (bean != null) {
              // 后置处理 调用BeanPostProcessor#postProcessAfterInitialization
               bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
            }
         }
      }
      mbd.beforeInstantiationResolved = (bean != null);
   }
   return bean;
}
wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
  // 已经处理过则无需处理
   if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
      return bean;
   }
  // 无需进行增强
   if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
      return bean;
   }
  // 如果是继承自Advice、Pointcut、Advisor、AopInfrastructureBean的类,或者@Aspect注解标注的类不需要代理
   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查找增强器
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, 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;
 }

// org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
protected List<Advisor> findCandidateAdvisors() {
  // Add all the Spring advisors found according to superclass rules.
  // 这里处理的是xml方式的
  List<Advisor> advisors = super.findCandidateAdvisors();
  // Build Advisors for all AspectJ aspects in the bean factory.
  // 解析@Aspect注解中的增强方法,进行解析
  advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
  return advisors;
 }
createProxy创建代理
protected Object createProxy(
      Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource)
 
{

   if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
      AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
   }

   ProxyFactory proxyFactory = new ProxyFactory();
   proxyFactory.copyFrom(this);
// 是接口需要代理还是类需要代理
   if (!proxyFactory.isProxyTargetClass()) {
      if (shouldProxyTargetClass(beanClass, beanName)) {
         proxyFactory.setProxyTargetClass(true);
      }
      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());
}

突然发现就创建个代理对象,spring考虑的是方方面面的,太强大了

何处调用的呢?

既然知道了AbstractAutoProxyCreator是BeanPostProcessor接口,那么就找到spring是在哪里调用的BeanPostProcessor。

是在createBean环节中的initializeBean初始化来进行调用的

Object exposedObject = bean;
try {
   populateBean(beanName, mbd, instanceWrapper);
   if (exposedObject != null) {
      exposedObject = initializeBean(beanName, exposedObject, mbd);
   }
}

来看一下initializeBean初始化中调用了哪些

// 执行的是Aware接口的对应方法 ((BeanNameAware) bean).setBeanName(beanName)、((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader())、((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this)
invokeAwareMethods(beanName, bean);
// 调用的是BeanPostProcessor的postProcessBeforeInitialization方法
applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
// 调用的是((InitializingBean) bean).afterPropertiesSet()以及自定义的init方法
invokeInitMethods(beanName, wrappedBean, mbd);
// 调用BeanPostProcessor的postProcessAfterInitialization方法
applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

可以看到有两个地方分别调用的BeanPostProcessor的postProcessBeforeInitialization方法、postProcessAfterInitialization方法,找到源头了

注意:

如果存在循环依赖的话,会在调用三级缓存中的ObjectFactory.getObject()进行aop代理,使得得到的早期对象是代理对象

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
   Object exposedObject = bean;
   if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
            SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
           // 这里做了个代理,也就是AOP  (AbstractAutoProxyCreator继承的SmartInstantiationAwareBeanPostProcessor,也就是在getEarlyBeanReference方法中调用的wrapIfNecessary方法)
            exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
            if (exposedObject == null) {
               return null;
            }
         }
      }
   }
   return exposedObject;
}

https://zhhll.icu/2022/框架/spring/进阶/7.AOP开启注解源码/

本文由 mdnice 多平台发布

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/594962.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

指挥中心操作台的选择至关重要

在指挥中心的环境中&#xff0c;操作台是核心设备&#xff0c;它承载着信息收集、处理、分发的重要任务。其选择应考虑到多方面的因素&#xff0c;包括外观、材质、稳定性、操作便利性以及技术支持等。嘉德立在这里给大家详细的总结一下选择指挥中心操作台的要点。 首先&#x…

5.Spring Security-web权限方案

设置登录的用户名和密码 1.通过配置文件设置用户名密码 spring:security:user:name: xiankejinpassword: 123456 如果没有以上配置&#xff0c;那么就会在后台生成一个随机密码&#xff0c;用户名固定位user。 2.通过配置类设置用户名密码 Configuration public class Sec…

【AIGC】深入探索AIGC技术在文本生成与音频生成领域的应用

&#x1f680;文章标题 &#x1f680;AIGC之文本生成&#x1f680;应用型文本生成&#x1f680;创作型文本生成&#x1f680;文本辅助生成&#x1f680;重点关注场景 &#x1f680;音频及文字—音频生成&#x1f680;TTS(Text-to-speech)场景&#x1f680;乐曲/歌曲生成&#x…

给股东送酱的公司值得关注吗?仲景食品-300908 年报分析(20240505)

仲景食品-300908 基本情况 公司名称&#xff1a;仲景食品股份有限公司 A股简称&#xff1a;仲景食品 成立日期&#xff1a;2002-09-29 上市日期&#xff1a;2020-11-23 所属行业&#xff1a;食品制造业 周期性&#xff1a;0 主营业务&#xff1a;调味配料和调味食品的研发、生产…

Android 14 变更及适配攻略

准备工作 首先将我们项目中的 targetSdkVersion和compileSdkVersion 升至 34。 影响Android 14上所有应用 1.最低可安装的目标 API 级别 从 Android 14 开始&#xff0c;targetSdkVersion 低于 23 的应用无法安装。要求应用满足这些最低目标 API 级别要求有助于提高用户的安…

跟TED演讲学英文:Is your partner “the one?“ Wrong question by George Blair-West

Is your partner “the one?” Wrong question Link: https://www.ted.com/talks/george_blair_west_is_your_partner_the_one_wrong_question Speaker: George Blair-West Date: December 2022 文章目录 Is your partner "the one?" Wrong questionIntroduction…

【Unity 组件思想-预制体】

【Unity 组件思想-预制体】 预制体&#xff08;Prefab&#xff09;是Unity中一种特殊的组件 特点和用途&#xff1a; 重用性&#xff1a; 预制体允许开发者创建可重复使用的自定义游戏对象。这意味着你可以创建一个预制体&#xff0c;然后在场景中多次实例化它&#xff0c;…

快速上手RabbitMQ

安装RabbitMQ 首先将镜像包上传到虚拟机&#xff0c;使用命令加载镜像 docker load -i mq.tar 运行MQ容器 docker run \-e RABBITMQ_DEFAULT_USERitcast \-e RABBITMQ_DEFAULT_PASS123321 \-v mq-plugins:/plugins \--name mq \--hostname mq \-p 15672:15672 \-p 5672:5672 …

图像识别——玩转YOLO网络

图像识别——玩转YOLO网络 YOLO&#xff0c;全称“You Only Look Once”&#xff0c;意为你只需要看一次&#xff0c;是一种快速、准确的目标检测算法。它由Joseph Redmon等人在2016年提出&#xff0c;其核心思想是将输入图像划分为SS个网格单元&#xff0c;每个网格预测B个边…

什么是脏读?幻读?不可重复读?

脏读(Drity Read)&#xff1a;某个事务 A 已更新一份数据&#xff0c;另一个事务 B 在此时读取了同一份数据&#xff0c;由于某些原因&#xff0c;事务 A 回滚&#xff0c;而事务B读取到事务 A 回滚前的数据。 例子:小明读取到小红提交的100数据.但是小红异常回滚了数据,100变…

STM32单片机实战开发笔记-PWM波输出频率及占空比配置【wulianjishu666】

单片机物联网开发资料&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1XzodQuML7CqZ4ZKinDGKkg?pwdbgep 提取码&#xff1a;bgep PWM模块测试 功能描述 脉冲宽度调制模式&#xff1a; PWM边沿对齐模式&#xff1a; 向上计数配置 当TIMX_CR1寄存器中的DIR为低的时…

Video2Game:革新游戏开发,重塑虚拟世界的未来

Video2Game&#xff1a;革新游戏开发&#xff0c;重塑虚拟世界的未来 一、Video2Game的提出与意义二、Video2Game的核心技术三、Video2Game的实现与应用四、代码实例与未来展望 在数字化和虚拟化日益盛行的今天&#xff0c;高质量的交互式虚拟环境&#xff0c;如游戏和模拟器&a…

TinTin Web3 Bounty 挑战杯第二期再启程,NEAR 生态邀请你来找 Bug!

对 Web3 来说&#xff0c;Bounty 任务应该是普通人获得行业“一杯羹”的重要捷径&#xff01; 通过深入学习各类 Web3 公链技术&#xff0c;凭借实战锻炼开发创新项目&#xff0c;或完善已有网络运行中出现的问题&#xff0c;就有机会更加快速了解其底层技术逻辑&#xff0c;更…

基于YOLOv8+PyQt5复杂场景下船舶目标检测系统

1. 应用场景 复杂场景下船舶目标检测系统的应用场景包括&#xff1a; 港口管理和安全&#xff1a;监控港口区域&#xff0c;确保船舶安全地进出港口&#xff0c;预防相撞事故的发生。 海洋交通监控&#xff1a;实时追踪海上交通流&#xff0c;并识别违规或异常航行行为&#x…

Python ValueError: bad transparency mask

修改前 修复后 运行正常 from PIL import Image# 读取图片 #报错信息解决ValueError: bad transparency mask--相关文档地址https://blog.csdn.net/kalath_aiur/article/details/103945309 #1. 检查 alpha 通道是否是一个有效的掩码。如果不是&#xff0c;则需要对 alpha 通道…

《Boundary Smooth for NER》

来源&#xff1a; ACL2022, 作者&#xff1a;中科院 命名实体识别(NER)模型很容易遇到over-confidence的问题&#xff0c;从而降低了性能。 基于边界存在的问题&#xff0c;参考 Label Smoothing&#xff0c;作者提出了 boundary smoothing 的训练方法&#xff0c;即使用 biaff…

苍穹外卖,接入redis cache后,新增套餐有问题

终端报错&#xff1a; java.lang.IllegalArgumentException: Null key returned for cache operation (maybe you are using named params on classes without debug info?) Builder[public com.sky.result.Result com.sky.controller.admin.SetmealController.save(com.sky.d…

Stable Diffusion WebUI 中文提示词插件 sd-webui-prompt-all-in-one

本文收录于《AI绘画从入门到精通》专栏,订阅后可阅读专栏内所有文章,专栏总目录:点这里。 大家好,我是水滴~~ 今天为大家介绍 Stable Diffusion WebUI 的一款中文提示词插件 sd-webui-prompt-all-in-one,就像它的名字一样,该插件几乎涵盖了提示词相关的所有功能。 文章内…

3D模型格式转换工具HOOPS Exchange如何读取建筑工程中复杂庞多的数据?

在当今数字化时代&#xff0c;建筑行业正日益依赖于复杂的3D建模工具和软件&#xff0c;以便在设计、规划和建造过程中实现更高的效率和精确性。然而&#xff0c;这种效率的提升往往伴随着一个挑战&#xff1a;不同软件之间的3D模型格式可能不兼容&#xff0c;这导致了数据转换…

SpringBootWeb创建

创建spring项目 创建SpringBoot工程定义请求处理类运行常见问题java: 无效的源发行版: XXjava: 无法访问org.springframework.web.bind.annotation.RequestMapping类文件具有错误的版本 61.0, 应为 52.0 创建SpringBoot工程 定义请求处理类 RestController public class HelloC…