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 多平台发布

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Springboot+vue项目零食销售商城

摘要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;零食销售商城当然也不能排除在外。零食销售商城是以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&#xff…

Golang编译优化——稀疏条件常量传播

文章目录 一、概述二、稀疏条件常量传播2.1 初始化worklist2.2 构建def-use链2.3 更新值的lattice2.4 传播constant值2.5 替换no-constant值 一、概述 常量传播&#xff08;constant propagation&#xff09;是一种转换&#xff0c;对于给定的关于某个变量 x x x和一个常量 c …

《米小圈上学记》|快乐读书,从身边的人身边的事开始!

时间&#xff0c;抓住了就是黄金&#xff0c;虚度了就是流水;书&#xff0c;看了就是学问&#xff0c;没看就是废纸:抱负&#xff0c;努力了才叫幻想&#xff0c;放弃了那只是妄想。读书&#xff0c;不一定能转变命运&#xff0c;但肯定能让我们安静&#xff0c;安静本身就是一…

红米1s 刷入魔趣 (Mokee)ROM(Android 7.1)

目录 背景准备工具硬件&#xff08;自己准备&#xff09;软件&#xff08;我会在文末提供链接&#xff09; 刷机步骤1. 重启电脑2. 安装驱动3. 刷入TWRP4. 清空数据5. 刷入魔趣6. 开机 结尾下载链接 本文由Jzwalliser原创&#xff0c;发布在CSDN平台上&#xff0c;遵循CC 4.0 B…

虚拟机jvm下

jvm原理与实践 java程序的跨平台特性 jvm基本结构 JVM类加载流程和内存结构总览 类加载 加载阶段 类加载 验证阶段 类加载 准备阶段 类加载 解析阶段 类加载 初始化阶段 程序计数器 虚拟机栈&本地方法栈 栈帧操作 堆 方法区 永久代 元空间 垃圾回收 可触及性

暗区突围国际服pc端海外版新手前期如何赚钱 暗区突围新手教学

暗区突围国际服pc端海外版新手前期如何赚钱 暗区突围新手教学 暗区突围是一款极为惊险的射击游戏&#xff0c;让玩家充分感受紧张激烈的战斗以及获取财富的过程。但是有许多新手玩家是不会在游戏里赚钱的&#xff0c;也会在赚钱过程中遇到很多问题&#xff0c;我将在这篇文章…

多线程【阻塞队列】(生产者消费者模型代码实现)

阻塞队列 解耦合削峰填谷生产者消费者模型&#xff1a; 解耦合 削峰填谷 生产者消费者模型&#xff1a; 正常来说&#xff0c;wait通过notify唤醒&#xff0c;其他线程调用了take,在take的最后一步进行notify. package thread; class MyBlockingQueue{private String [] data…

细胞自动机与森林火灾与燃烧模拟

基于 元胞自动机-森林火灾模拟_vonneumann邻域-CSDN博客 进行略微修改&#xff0c;解决固定方向着火问题&#xff0c;用了一个meshv2数组记录下一状态&#xff0c;避免旧状态重叠数据失效。 参数调整 澳洲森林火灾蔓延数学建模&#xff0c;基于元胞自动机模拟多模式下火灾蔓延…

【牛客】【模板】二维前缀和

原题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 二维前缀和板题。 二维前缀和&#xff1a;pre[i][j]a[i][j]pre[i-1][j]pre[i][j-1]-pre[i-1][j-1]; 子矩阵 左上角为(x1,y1) 右下角(x2,y2…

.OpenNJet应用引擎实践——从 0-1 体验感受

目录 一. &#x1f981; 写在前面二. &#x1f981; 安装使用2.1 安装环境2.2 配置yum源2.3 安装软件包2.4 编译代码2.5 启动 三. &#x1f981; 使用效果3.1 编辑配置文件3.2 编辑 HTML 代码 四. &#x1f981; 使用感受 一. &#x1f981; 写在前面 现在互联网体系越来越往云…

记录PR学习查漏补缺(持续补充中。。。)

记录PR学习查漏补缺 常用快捷键文件编辑素材序列标记字幕窗口帮助 效果基本3D高斯模糊查找边缘色彩颜色平衡超级键马赛克中间值变形稳定器轨道遮罩键 常用 快捷键 注意&#xff1a;比较常用的用红色字体显示 文件 快捷键作用Ctrl Alt N新建项目Ctrl O打开项目Ctrl I导入…

JRT失控处理打印和演示

基于JRT完备的脚本化和打印基础&#xff0c;基于JRT的业务可以轻松的实现想要的打效果&#xff0c;这次以质控图的失控处理打印和月报打印来分享基于JRT的打印业务实现。 演示视频链接 失控报告打印 失控处理打印的虚拟M import JRT.Core.DataGrid.GridDto; import JRT.Co…

Konga域名配置多个路由

云原生API网关-Kong部署与konga基本使用 Nginx server{listen 443 ssl;location / {proxy_pass http://127.0.0.1:8100;}location /openApi {proxy_pass http://172.31.233.35:7100/openApi;} } Kong {"id": "f880b21c-f7e0-43d7-a2a9-221fe86d9231&q…

通过AOP实现项目中业务服务降级功能

最近项目中需要增强系统的可靠性&#xff0c;比如某远程服务宕机或者网络抖动引起服务不可用&#xff0c;需要从本地或者其它地方获取业务数据&#xff0c;保证业务的连续稳定性等等。这里简单记录下业务实现&#xff0c;主要我们项目中调用远程接口失败时&#xff0c;需要从本…

Nest.js中使用任务调度

java中的xxl在nestJs中是有内置的任务调度nestjs/schedule npm install --save nestjs/schedule 在model中引入使用 在service中直接使用就行 具体间隔多久看官方配置 Task Scheduling | NestJS 中文文档 | NestJS 中文网

微信小程序开发-数据事件绑定

&#x1f433;简介 数据绑定 数据绑定是一种将小程序中的数据与页面元素关联起来的技术&#xff0c;使得当数据变化时&#xff0c;页面元素能够自动更新。这通常使用特定的语法&#xff08;如双大括号 {{ }}&#xff09;来实现&#xff0c;以便在页面上展示动态数据。 事件绑…

小微公司可用的开源ERP系统

项目介绍 华夏ERP是基于SpringBoot框架和SaaS模式的企业资源规划&#xff08;ERP&#xff09;软件&#xff0c;旨在为中小企业提供开源且易用的ERP解决方案。它专注于提供进销存、财务和生产功能&#xff0c;涵盖了零售管理、采购管理、销售管理、仓库管理、财务管理、报表查询…

VALSE 2024 Workshop报告分享┆ 大规模自动驾驶仿真系统研究

视觉与学习青年学者研讨会&#xff08;VALSE&#xff09;旨在为从事计算机视觉、图像处理、模式识别与机器学习研究的中国青年学者提供一个广泛而深入的学术交流平台。该平台旨在促进国内青年学者的思想交流和学术合作&#xff0c;以期在相关领域做出显著的学术贡献&#xff0c…

【三】DRF序列化进阶

序列化器的定义与使用 多表关联序列化 【1】准备工作 # settings.py DATABASES {default: {# 数据库引擎选择使用MySQLENGINE: django.db.backends.mysql,# 指定数据库名字&#xff0c;需提前创建NAME: books,# 指定数据库用户名USER: root,# 指定数据库用户密码PASSWORD: …

嵌入式学习69-C++(Opencv)

知识零碎&#xff1a; QT的两种编译模式 1.debug 调试模式 …