Spring高手之路20——深入理解@EnableAspectJAutoProxy的力量

文章目录

  • 1. 初始调试代码
  • 2. 源码跟踪分析
    • 2.1 初探@EnableAspectJAutoProxy
    • 2.2 registerBeanDefinitions方法和时序图分析
    • 2.3 registerOrEscalateApcAsRequired方法和时序图分析

1. 初始调试代码

  面向切面编程(AOP)是一种编程范式,用于增强软件模块化,通过将横切关注点(如事务管理、安全等)分离出业务逻辑。Spring AOPSpring框架中实现AOP的一种方式,它通过代理机制在运行时向对象动态地添加增强。AspectJ是一种更强大的AOP实现,它通过编译时和加载时织入,提供了比Spring AOP更丰富的增强选项。本文将探索如何通过Spring AOP进行简单的AOP配置和实现。

后续源码分析就用这个前置通知的代码调试

package com.example.demo.aspect;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;@Aspect
@Component
public class MyAspect {@Before("execution(* com.example.demo.service.MyService.performAction(..))")public void beforeAdvice(JoinPoint joinPoint) {System.out.println("Before method: " + joinPoint.getSignature().getName());}
}
package com.example.demo.configuration;import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}
package com.example.demo.service;import org.springframework.stereotype.Service;// 一个简单的服务类
@Service
public class MyService {public void performAction() {System.out.println("Performing an action");}
}
package com.example.demo;import com.example.demo.service.MyService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;//主应用类
@ComponentScan(basePackages = "com.example.demo")
public class DemoApplication {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DemoApplication.class);MyService myService = context.getBean(MyService.class);myService.performAction();  // 调用方法,触发AOP增强}
}

2. 源码跟踪分析

2.1 初探@EnableAspectJAutoProxy

  上面代码中,AppConfig配置类里有个@EnableAspectJAutoProxy注解,前面说过,@EnableAspectJAutoProxy注解告诉Spring框架去寻找带有@Aspect注解的类,Spring AOP通过读取@EnableAspectJAutoProxy注解的属性来配置代理的行为。

下面用时序图来展示通过@EnableAspectJAutoProxy注解启用面向切面编程(AOP)的过程。

在这里插入图片描述

解读:

  1. 启动ApplicationContext
  • 应用 (App) 向 ApplicationContext 发送消息以启动Spring的应用上下文。这是Spring应用的初始化阶段,负责设置Spring的核心功能,包括Bean的加载和管理。
  1. 加载配置类
  • ApplicationContext 接着加载 配置类 (ConfigClass)。这个配置类包含了应用的配置信息,如Bean定义和AOP支持的相关注解等。
  1. 检测@EnableAspectJAutoProxy
  • 配置类完成加载后,检查是否包含 @EnableAspectJAutoProxy 注解。此注解是启用Spring AOP代理的关键,它指示Spring框架自动为符合条件的Bean创建AOP代理。
  1. 注册AspectJAutoProxyCreator
  • 一旦检测到@EnableAspectJAutoProxy注解,ApplicationContext 会注册 AspectJAutoProxyCreator (APC)。这个组件是一个BeanPostProcessor,它在Spring容器的bean初始化阶段介入,自动检测容器中所有带有@Aspect注解的类,并为这些类创建代理。这个代理创建过程不仅包括实现通知逻辑的织入,还涉及对被代理对象的调用进行拦截,确保在执行目标方法前后能够执行相应的通知(advice)。
  1. 扫描和注册Beans
  • ApplicationContext 继续扫描应用中的其他 Bean,并将它们注册到Spring容器中。这包括普通的Bean和那些可能成为AOP代理目标的Bean
  1. 识别@Aspect注解
  • Bean的扫描过程中,识别出带有 @Aspect 注解的BeanAspectBean)。这些Bean定义了AOP的切面,如通知方法(advice),指定在某些方法执行前后或抛出异常时执行。
  1. 请求创建代理
  • 当识别到@Aspect注解的Bean时,这些Bean会向 AspectJAutoProxyCreator 发出请求,要求创建相应的代理。
  1. 调用创建代理
  • AspectJAutoProxyCreator 收到创建代理的请求后,调用代理工厂 (ProxyFactory) 来构建具体的代理实例。
  1. 构建代理Bean
  • 代理工厂 根据AspectJAutoProxyCreator的指示,为@Aspect注解的Bean创建代理。这些代理将封装原Bean,并在调用原Bean的方法时,按照@Aspect定义执行相应的前置、后置或异常通知。
  1. 注册代理Bean
  • 创建完成的代理BeanProxyBean)被注册回 ApplicationContext,替换或增加到原有的Bean配置中。
  1. 完成Bean加载和初始化
  • 所有Bean,包括新注册的代理Bean,都被加载和初始化后,ApplicationContext 向应用 (App) 发送消息,表示Bean加载和初始化工作已完成,应用可以开始执行。

来看看源码,这里可以看到@Import 导入了一个注册器AspectJAutoProxyRegistrar

在这里插入图片描述
  @EnableAspectJAutoProxy注解启用Spring的自动代理机制,该注解有两个重要的属性配置:proxyTargetClassexposeProxyproxyTargetClass属性默认为false,此时Spring使用JDK动态代理来代理接口。如果设置为true,则Spring将使用CGLIB来代理类,这在目标对象没有实现接口时特别有用。exposeProxy属性默认为false,如果设置为true,允许通过AopContext类访问当前的代理对象,这在需要在目标对象内部方法调用自身被代理的方法时非常有用。

2.2 registerBeanDefinitions方法和时序图分析

本节源码都基于5.3.16分析。

这段代码主要涉及2.1节时序图中的“加载配置类”和“注册AspectJAutoProxyCreator”这两个步骤。
AspectJAutoProxyRegistrar类的registerBeanDefinitions方法打上断点调试。

在这里插入图片描述

  这个方法主要负责根据@EnableAspectJAutoProxy注解的设置来配置Spring AOP的行为,包括是否使用CGLIB进行类代理而不是基于接口的JDK代理,以及是否允许在被代理的对象内部通过AopContext访问代理对象。这两个设置对于控制Spring AOP的行为至关重要,特别是在处理复杂的代理场景和高级AOP功能时。

代码提出来分析:

// 注册Bean定义的方法,通过读取注解元数据和操作Bean定义注册表进行配置
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {// 检查是否已经注册了AspectJ自动代理创建器,如果没有,则进行注册AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);// 从导入的类的注解元数据中获取@EnableAspectJAutoProxy注解的属性AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);// 检查是否成功获取@EnableAspectJAutoProxy注解的属性if (enableAspectJAutoProxy != null) {// 检查@EnableAspectJAutoProxy注解的proxyTargetClass属性是否为trueif (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {// 如果proxyTargetClass为true,则强制AOP代理创建器使用CGLIB来进行类代理AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);}// 检查@EnableAspectJAutoProxy注解的exposeProxy属性是否为trueif (enableAspectJAutoProxy.getBoolean("exposeProxy")) {// 如果exposeProxy为true,则强制AOP代理创建器暴露代理对象,使其能在被代理的对象内部通过AopContext访问AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);}}
}

这个方法的两个入参说明一下:

  1. importingClassMetadataAnnotationMetadata类型的实例,它持有关于当前正在被处理的类的注解信息。这里用来检索有关@EnableAspectJAutoProxy注解的信息,这些信息决定了如何配置AOP代理的行为(是否使用CGLIB代理以及是否暴露代理对象)。

  2. registryBeanDefinitionRegistry类型的实例,它是一个用于注册Bean定义的接口。通过这个注册表,可以在运行时向Spring应用上下文添加新的Bean定义或修改现有的Bean定义。这里用于实际调整AOP配置,如注册AOP代理创建器,以及设置代理创建器的行为(根据@EnableAspectJAutoProxy的属性值)。这些操作直接影响了Spring AOP如何在运行时创建和管理AOP代理。

如果流程太抽象,那么用时序图补充

在这里插入图片描述

  这个时序图展示了Spring AOP配置的完整流程,从检查和注册自动代理创建器,到根据@EnableAspectJAutoProxy注解的设置调整Spring的代理行为。此过程确保了应用的AOP配置能够根据给定的注解属性正确地执行,无论是使用更高性能的CGLIB代理,还是暴露代理以供内部访问。

完整的时序图解释

1. 方法调用开始

  • 调用者 (Caller)触发 registerBeanDefinitions 方法(RBD),这通常发生在应用的配置阶段。

2. 检查并注册自动代理创建器

  • registerBeanDefinitionsAopConfigUtilsAopCU)发起调用,检查是否已注册AspectJ自动代理创建器,或者是否需要注册新的或更新现有的代理创建器。

3. 自动代理创建器的注册和更新

  • AopConfigUtilsRegistryReg)执行实际的注册或更新操作。
  • Registry 完成更新后反馈给 AopConfigUtils
  • AopConfigUtils 然后将结果返回给 registerBeanDefinitions

4. 获取@EnableAspectJAutoProxy注解的属性

  • registerBeanDefinitions 接着从 AnnotationConfigUtilsACU)获取@EnableAspectJAutoProxy注解的相关属性,这些属性决定代理的行为。

5. 根据属性设置代理方式

  • 如果注解的proxyTargetClass属性为真,意味着需要使用CGLIB来进行类代理而不是基于接口的代理。
  • registerBeanDefinitions 要求 AopConfigUtils 强制使用CGLIB代理。
  • AopConfigUtils 更新 Registry 中相关Bean定义的设置以使用CGLIB
  • Registry 确认设置已更新,然后 AopConfigUtils 通知 registerBeanDefinitions 配置完成。

6. 设置是否暴露代理

  • 如果注解的exposeProxy属性为真,意味着需要暴露代理,允许通过AopContext访问当前代理。
  • registerBeanDefinitions 要求 AopConfigUtils 强制暴露代理。
  • AopConfigUtilsRegistry 中进行相应设置更新。
  • Registry 确认设置已更新,然后 AopConfigUtils 通知 registerBeanDefinitions 配置完成。

7. 配置流程完成

  • 一旦所有设置完成,registerBeanDefinitions 向调用者报告配置流程已完成。

2.3 registerOrEscalateApcAsRequired方法和时序图分析

看到刚刚第一句注册后置处理器,我们来详细看看

在这里插入图片描述
  这段代码主要与2.1节时序图中的“注册AspectJAutoProxyCreator”步骤相对应。AspectJAutoProxyCreator是由Spring内部管理的一个自动代理创建器,用于基于AspectJ的注解来创建AOP代理。它与用户定义的切面(使用@Aspect注解的类)相区分,后者指定了具体的通知(如@Before, @AfterReturning等)和切点表达式。在SpringAOP实现中,代理创建器负责实际的代理对象创建工作,而用户定义的切面提供了应用于这些代理对象的通知逻辑。具体而言,它描述了如何在SpringApplicationContext中检查并可能更新或注册一个新的自动代理创建器(AspectJAutoProxyCreator)。

直接分析registerOrEscalateApcAsRequired方法

// 定义一个用于注册或升级自动代理创建器的静态方法
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {// 断言,确保传入的registry不为空Assert.notNull(registry, "BeanDefinitionRegistry must not be null");// 检查容器是否已经包含名为"org.springframework.aop.config.internalAutoProxyCreator"的Bean定义if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {// 获取已存在的自动代理创建器的Bean定义BeanDefinition apcDefinition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");// 检查当前注册的自动代理创建器类名是否与传入的cls类名不同if (!cls.getName().equals(apcDefinition.getBeanClassName())) {// 找到当前自动代理创建器的优先级int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());// 找到需要注册的自动代理创建器的优先级int requiredPriority = findPriorityForClass(cls);// 比较两个优先级,若已注册的优先级低,则更新为新的自动代理创建器类if (currentPriority < requiredPriority) {apcDefinition.setBeanClassName(cls.getName());}}// 若已存在自动代理创建器且不需要升级,则返回nullreturn null;} else {// 若未注册自动代理创建器,则创建一个新的RootBeanDefinition实例RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);// 设置bean定义的来源beanDefinition.setSource(source);// 设置bean定义的属性,这里设置"order"属性为最小整数值,表示最高优先级beanDefinition.getPropertyValues().add("order", Integer.MIN_VALUE);// 设置bean定义的角色,通常ROLE_INFRASTRUCTURE表示框架内部使用的组件beanDefinition.setRole(2);// 在注册表中注册名为"org.springframework.aop.config.internalAutoProxyCreator"的新自动代理创建器Bean定义registry.registerBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator", beanDefinition);// 返回新创建的Bean定义return beanDefinition;}
}

  这个方法主要用于控制Spring AOP框架中的自动代理创建器(AutoProxyCreator)的注册与优先级升级,确保AOP功能按预期工作,特别是在有多个自动代理创建器可能存在时确保正确的配置和行为优先级。

  自动代理创建器(AutoProxyCreator)是一个核心组件,根据配置(如注解、XML配置或程序的指定)识别需要增强的Bean,并自动为这些Bean创建代理。这些代理可以在方法调用前后添加额外的行为,而不修改原有代码的基础上,实现如安全检查、事务管理、日志记录等横切关注点。

如果流程太抽象,那么用时序图补充

在这里插入图片描述

  这个时序图展示了 registerOrEscalateApcAsRequired 方法如何根据已存在的自动代理创建器Bean定义的情况来决定执行的操作。通过检查、比较和可能的更新或创建操作,它确保了最适合的类被用于自动代理创建器。如果当前注册的自动代理创建器足够适合,不会进行更改;如果不适合,会进行更新或创建新的Bean定义,以保证系统配置的最优化。

1. 开始调用

  • 调用者发起对 registerOrEscalateApcAsRequired 方法的调用。该方法接收三个参数:类(cls),注册表(registry)和源信息(source)。

2. 检查Bean定义是否存在

  • registerOrEscalateApcAsRequiredBeanDefinitionRegistry 查询是否已存在名为 “internalAutoProxyCreator” 的Bean定义。

3. 处理已存在的Bean定义

  • 如果 BeanDefinitionRegistry 确认Bean定义已存在(返回true),registerOrEscalateApcAsRequiredBeanDefinitionRegistry 请求获取该Bean定义。
  • BeanDefinitionRegistryBeanDefinition 返回给 registerOrEscalateApcAsRequired
  • registerOrEscalateApcAsRequired 使用返回的 BeanDefinition 检查并比较当前Bean的类与新传入的类 cls 的优先级。

4. 决定是否更新Bean定义

  • 如果新类 cls 的优先级更高,registerOrEscalateApcAsRequired 会在 BeanDefinition 中更新类名为新类 cls.getName()
  • 更新操作完成后,BeanDefinition 通知 BeanDefinitionRegistry 更新已完成。
  • 如果当前已注册的类的优先级足够高或相同,不需要进行更新,registerOrEscalateApcAsRequired 直接返回null给调用者。

5. 处理不存在的Bean定义

  • 如果 BeanDefinitionRegistry 确认没有找到名为 “internalAutoProxyCreator” 的Bean定义(返回false),registerOrEscalateApcAsRequired 将创建一个新的 BeanDefinition
  • 新创建的 BeanDefinition 被注册到 BeanDefinitionRegistry
  • 注册完成后,BeanDefinitionRegistry 确认新的BeanDefinition已注册。
  • registerOrEscalateApcAsRequired 最终将新创建的BeanDefinition返回给调用者。

欢迎一键三连~

有问题请留言,大家一起探讨学习

----------------------Talk is cheap, show me the code-----------------------

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

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

相关文章

异常向量表的设置

1、Linux Kernel中对异常向量表的填充 linux/arch/arm64/kernel/entry.S kernel_ventry 是一个定义异常向量的宏&#xff1b; 在该宏中&#xff0c;程序跳转到了b el\el\ht()\regsize()\label; 以为异常向量的第6行为例&#xff0c;其实就是跳转到了bl el1h_64_irq; 然后你去搜…

Docker部署Nginx下载站点服务

1、下载镜像 由于docker官方镜像站点被封了&#xff0c;所以我把镜像上传到阿里云镜像仓库了 docker pull registry.cn-hangzhou.aliyuncs.com/qinzt-tools/file-nginx:1.18.02、运行容器实例 运行变量解释&#xff1a; 变量名称默认值解释USERhyadmin访问下载站点的认证用…

集成学习方法:Bagging与Boosting的应用与优势

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

Python基础用法 之 数据类型

Python常见数据类型分类 数字型非数字型整型&#xff1a; 整数--int--16 字符串&#xff1a;使用引号引起来的的就是字符串--Tom 浮点型&#xff1a;小数--float--16.66列表&#xff1a;list [1,2,3] 布尔型&#xff1a;bool&#xff08;真True&#xff0c;假False&#xff…

创建STM32F10X空项目教程

创建STM32F10X系列的空项目工程 官网下载STM32标准外设软件库 STM32标准外设软件库 创建一个空文件夹作为主工程文件夹在主工程文件夹中&#xff0c;创建三个空文件夹 CMSIS - 存放内核函数及启动引导文件 FWLIB - 存放库函数 USER - 存放用户的函数将STM32标准外设软件库文件…

OpenCV中 haarcascades 级联分类器各种模型.xml文件介绍

haarcascades Haar Cascades 是一种用于对象检测的机器学习模型&#xff0c;特别是在OpenCV库中广泛使用。这些模型通过训练大量的正样本&#xff08;包含目标对象的图像&#xff09;和负样本&#xff08;不包含目标对象的图像&#xff09;来识别图像中的对象。Haar Cascades …

【UML用户指南】-16-对高级结构建模-构件

目录 1、概念 2、构件与接口 3、可替换性 4、组织构件 5、端口 6、内部结构 6.1、部件 6.2、连接件 7、常用建模技术 7.1、对结构类建模 7.2、对API建模 构件是系统中逻辑的并且可替换的部分&#xff0c;它遵循并提供对一组接口的实现。好的构件用定义良好的接口来定…

XML Encoding = ‘GBK‘ after STRANS,中文乱码

最近帮同事处理了一个中信银行银企直连接口的一个问题,同事反馈,使用STRANS转换XML后,encoding始终是’utf-16’,就算指定了GBK也不行。尝试了很多办法始终不行,发到银行的数据中,中文始终是乱码。 Debug使用HTML视图看报文时也可以看到中文是乱码。 解决方案: 使用cl…

高考志愿填报,如何选择大学专业?

选择大学专业是一件需要谨慎的事情&#xff0c;需要综合考虑各个因素。大学专业和将来的就业方向是一致的&#xff0c;选专业实际就是在选职业&#xff0c;选自己未来几十年的职业生活。如何去选择大学专业&#xff0c;建议从个人兴趣&#xff0c;个人优势能力&#xff0c;职业…

C/C++ Adaline自适应线性神经网络算法详解及源码

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

高阶数据结构[2]图的初相识

图的初相识 1.前言 2.图的概念 3.图的相关术语 4.图的存储结构 4.1邻接矩阵 4.2邻接表 4.3两种存储方式的对比 5.图的存储实现 5.1邻接矩阵的实现 5.2邻接表的实现 6.总结 1.前言 本章将大家学习数据结构中的“图”。有学习过离散数学的同学对这一章节或许会比…

【归并排序】| 详解归并排序核心代码之合并两个有序数组 力扣88

&#x1f397;️ 主页&#xff1a;小夜时雨 &#x1f397;️专栏&#xff1a;动态规划 &#x1f397;️如何活着&#xff0c;是我找寻的方向 目录 1. 题目解析2. 代码 1. 题目解析 题目链接: https://leetcode.cn/problems/merge-sorted-array/description/ 本道题是归并排序的…

超拟人大模型:AI心理健康服务的未来

摘要&#xff1a; 周末听了一场聆心智能关于情感LLM的分享&#xff0c;总结了相关内容如下。在人工智能技术的浪潮中&#xff0c;超拟人大模型技术为心理健康服务领域带来了革命性的变化。本文将分析超拟人大模型的进展、CharacterGLM模型的特点、Emohaa模型的应用以及心理健康…

AI 挑战周杰伦?Suno 全新功能面世,即兴哼几句就能创作成歌,还能模仿声音!...

作者 | 王启隆 出品丨AI 科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09; 2016 年&#xff0c;周杰伦根据女儿 Hathaway 在玩具钢琴上随意弹出的几个音符&#xff0c;激发出创作的灵感&#xff0c;谱写了一首温馨而深情的歌曲——《前世情人》。8 年过去&#xff0…

【每日随笔】摩托车控车 ① ( 油离配合 | 落脚油离配合 - 不给油 | 落脚油离配合 - 给油 | 正式油离配合 | 骑行姿态注意事项 )

文章目录 一、找 " 离合结合点 "二、落脚油离配合 ( 不给油 )1、该科目练习目的2、起步姿态3、开始练习 三、落脚油离配合 ( 给油 )1、练习目的2、熟悉油门转速3、练习步骤 四、正式油离配合1、练习目的2、练习步骤3、练习效果 五、骑行姿态注意事项1、基本骑行姿态2…

Cisco Packet Tracer实验(四)

生成树协议&#xff08;Spanning Tree Protocol&#xff09; 交换机在目的地址未知或接收到广播帧时是要进行广播的。如果交换机之间存在回路/环路&#xff0c;那么就会产生广播循环风暴&#xff0c;从而严重影响网络性能。 而交换机中运行的STP协议能避免交换机之间发生广播…

解决Qt的multimedia库在clion中依赖库补全的问题

解决Qt的multimedia库在clion中使用报错的问题 在clion中&#xff0c;使用Qt的multimedia库时会报如下错误&#xff1a; defaultServiceProvider::requestService(): no service found for - "org.qt-project.qt.mediaplayer" 我猜测出现这个错误的原因很可能是因为…

迅狐短视频矩阵管理系统核心功能

一、多平台管理&#xff1a;连接多个主流自媒体平台&#xff0c;满足多平台、多账号、多角色的协调需求 在现如今的多元化媒体环境中&#xff0c;一个优秀的内容创作者需要同时管理多个自媒体平台&#xff0c;并以不同的身份角色展现自己。迅狐短视频矩阵管理系统强大的多平台…

数据结构重要知识总结

数组 数组&#xff08;Array&#xff09; 是一种很常见的数据结构。它由相同类型的元素&#xff08;element&#xff09;组成&#xff0c;并且是使用一块连续的内存来存储。 我们直接可以利用元素的索引&#xff08;index&#xff09;可以计算出该元素对应的存储地址。 数组…

如何充分利用 Postgres 的内存设置

为了充分利用 PostgreSQL 的内存设置&#xff0c;你需要调整多个参数以优化数据库性能。这些参数包括共享缓冲区&#xff08;shared_buffers&#xff09;、工作内存&#xff08;work_mem&#xff09;、维护工作内存&#xff08;maintenance_work_mem&#xff09;、有效缓存大小…