当前位置: 首页 > news >正文

聊聊druid连接池的监控

本文主要研究一下druid连接池的监控

init

com/alibaba/druid/pool/DruidDataSource.java

public void init() throws SQLException {//......registerMbean();//......
}

DruidDataSource的init方法会执行registerMbean

registerMbean

com/alibaba/druid/pool/DruidDataSource.java

    public void registerMbean() {if (!mbeanRegistered) {AccessController.doPrivileged(new PrivilegedAction<Object>() {@Overridepublic Object run() {ObjectName objectName = DruidDataSourceStatManager.addDataSource(DruidDataSource.this,DruidDataSource.this.name);DruidDataSource.this.setObjectName(objectName);DruidDataSource.this.mbeanRegistered = true;return null;}});}}

registerMbean会执行DruidDataSourceStatManager.addDataSource(DruidDataSource.this, DruidDataSource.this.name)

DruidDataSourceStatManager

com/alibaba/druid/stat/DruidDataSourceStatManager.java

    public static synchronized ObjectName addDataSource(Object dataSource, String name) {final Map<Object, ObjectName> instances = getInstances();MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();synchronized (instances) {if (instances.size() == 0) {try {ObjectName objectName = new ObjectName(MBEAN_NAME);if (!mbeanServer.isRegistered(objectName)) {mbeanServer.registerMBean(instance, objectName);}} catch (JMException ex) {LOG.error("register mbean error", ex);}DruidStatService.registerMBean();}}ObjectName objectName = null;if (name != null) {try {objectName = new ObjectName("com.alibaba.druid:type=DruidDataSource,id=" + name);mbeanServer.registerMBean(dataSource, objectName);} catch (Throwable ex) {LOG.error("register mbean error", ex);objectName = null;}}if (objectName == null) {try {int id = System.identityHashCode(dataSource);objectName = new ObjectName("com.alibaba.druid:type=DruidDataSource,id=" + id);mbeanServer.registerMBean(dataSource, objectName);} catch (Throwable ex) {LOG.error("register mbean error", ex);objectName = null;}}instances.put(dataSource, objectName);return objectName;}

DruidDataSourceStatManager的addDataSource方法通过mbeanServer.registerMBean(dataSource, objectName)将DruidDataSource注册到mbeanServer中,而DruidDataSource则实现了DruidDataSourceMBean接口

DruidDataSourceMBean

public interface DruidDataSourceMBean extends DruidAbstractDataSourceMBean {long getResetCount();boolean isEnable();String getUrl();void shrink();int removeAbandoned();String dump();int getWaitThreadCount();int getLockQueueLength();long getNotEmptyWaitCount();int getNotEmptyWaitThreadCount();long getNotEmptySignalCount();long getNotEmptyWaitMillis();long getNotEmptyWaitNanos();void resetStat();boolean isResetStatEnable();void setResetStatEnable(boolean resetStatEnable);String getVersion();void setPoolPreparedStatements(boolean poolPreparedStatements);int getActivePeak();int getPoolingPeak();Date getActivePeakTime();Date getPoolingPeakTime();long getErrorCount();ObjectName getObjectName();void clearStatementCache() throws SQLException;long getDiscardCount();void setStatLoggerClassName(String className);long getTimeBetweenLogStatsMillis();void setTimeBetweenLogStatsMillis(long timeBetweenLogStatsMillis);void setConnectionProperties(String connectionProperties);int fill() throws SQLException;int fill(int toCount) throws SQLException;boolean isUseGlobalDataSourceStat();
}

DruidDataSourceMBean按jmx规范命名以MBean结尾,它定义了一系列的getter和操作方法,它还继承了DruidAbstractDataSourceMBean

DruidAbstractDataSourceMBean

com/alibaba/druid/pool/DruidAbstractDataSourceMBean.java

public interface DruidAbstractDataSourceMBean {int getLoginTimeout();String getDbType();String getName();int getInitialSize();String getUsername();String getUrl();String getDriverClassName();long getConnectCount();long getCloseCount();long getConnectErrorCount();int getPoolingCount();long getRecycleCount();int getActiveCount();long getCreateCount();long getDestroyCount();long getCreateTimespanMillis();long getCommitCount();long getRollbackCount();long getStartTransactionCount();int getQueryTimeout();int getTransactionQueryTimeout();String getValidationQuery();int getValidationQueryTimeout();int getMaxWaitThreadCount();long getTimeBetweenEvictionRunsMillis();long getMinEvictableIdleTimeMillis();boolean isRemoveAbandoned();long getRemoveAbandonedTimeoutMillis();List<String> getActiveConnectionStackTrace();List<String> getFilterClassNames();boolean isTestOnBorrow();void setTestOnBorrow(boolean testOnBorrow);boolean isTestOnReturn();boolean isTestWhileIdle();void setTestWhileIdle(boolean testWhileIdle);boolean isDefaultAutoCommit();Boolean getDefaultReadOnly();Integer getDefaultTransactionIsolation();String getDefaultCatalog();boolean isPoolPreparedStatements();boolean isSharePreparedStatements();long getMaxWait();int getMinIdle();int getMaxIdle();long getCreateErrorCount();int getMaxActive();void setMaxActive(int maxActive);long getTimeBetweenConnectErrorMillis();int getMaxOpenPreparedStatements();long getRemoveAbandonedCount();boolean isLogAbandoned();void setLogAbandoned(boolean logAbandoned);long getDupCloseCount();boolean isBreakAfterAcquireFailure();int getConnectionErrorRetryAttempts();int getMaxPoolPreparedStatementPerConnectionSize();void setMaxPoolPreparedStatementPerConnectionSize(int maxPoolPreparedStatementPerConnectionSize);String getProperties();int getRawDriverMinorVersion();int getRawDriverMajorVersion();Date getCreatedTime();String getValidConnectionCheckerClassName();long[] getTransactionHistogramValues();void setTransactionThresholdMillis(long transactionThresholdMillis);long getTransactionThresholdMillis();long getPreparedStatementCount();long getClosedPreparedStatementCount();long getCachedPreparedStatementCount();long getCachedPreparedStatementDeleteCount();long getCachedPreparedStatementAccessCount();long getCachedPreparedStatementMissCount();long getCachedPreparedStatementHitCount();boolean isUseOracleImplicitCache();void setUseOracleImplicitCache(boolean useOracleImplicitCache);int getDriverMajorVersion();int getDriverMinorVersion();String getExceptionSorterClassName();
}

DruidAbstractDataSourceMBean定义了暴露给jmx的一系列方法

getStatDataForMBean

com/alibaba/druid/pool/DruidDataSource.java

    public Map<String, Object> getStatDataForMBean() {try {Map<String, Object> map = new HashMap<String, Object>();// 0 - 4map.put("Name", this.getName());map.put("URL", this.getUrl());map.put("CreateCount", this.getCreateCount());map.put("DestroyCount", this.getDestroyCount());map.put("ConnectCount", this.getConnectCount());// 5 - 9map.put("CloseCount", this.getCloseCount());map.put("ActiveCount", this.getActiveCount());map.put("PoolingCount", this.getPoolingCount());map.put("LockQueueLength", this.getLockQueueLength());map.put("WaitThreadCount", this.getNotEmptyWaitThreadCount());// 10 - 14map.put("InitialSize", this.getInitialSize());map.put("MaxActive", this.getMaxActive());map.put("MinIdle", this.getMinIdle());map.put("PoolPreparedStatements", this.isPoolPreparedStatements());map.put("TestOnBorrow", this.isTestOnBorrow());// 15 - 19map.put("TestOnReturn", this.isTestOnReturn());map.put("MinEvictableIdleTimeMillis", this.minEvictableIdleTimeMillis);map.put("ConnectErrorCount", this.getConnectErrorCount());map.put("CreateTimespanMillis", this.getCreateTimespanMillis());map.put("DbType", this.dbTypeName);// 20 - 24map.put("ValidationQuery", this.getValidationQuery());map.put("ValidationQueryTimeout", this.getValidationQueryTimeout());map.put("DriverClassName", this.getDriverClassName());map.put("Username", this.getUsername());map.put("RemoveAbandonedCount", this.getRemoveAbandonedCount());// 25 - 29map.put("NotEmptyWaitCount", this.getNotEmptyWaitCount());map.put("NotEmptyWaitNanos", this.getNotEmptyWaitNanos());map.put("ErrorCount", this.getErrorCount());map.put("ReusePreparedStatementCount", this.getCachedPreparedStatementHitCount());map.put("StartTransactionCount", this.getStartTransactionCount());// 30 - 34map.put("CommitCount", this.getCommitCount());map.put("RollbackCount", this.getRollbackCount());map.put("LastError", JMXUtils.getErrorCompositeData(this.getLastError()));map.put("LastCreateError", JMXUtils.getErrorCompositeData(this.getLastCreateError()));map.put("PreparedStatementCacheDeleteCount", this.getCachedPreparedStatementDeleteCount());// 35 - 39map.put("PreparedStatementCacheAccessCount", this.getCachedPreparedStatementAccessCount());map.put("PreparedStatementCacheMissCount", this.getCachedPreparedStatementMissCount());map.put("PreparedStatementCacheHitCount", this.getCachedPreparedStatementHitCount());map.put("PreparedStatementCacheCurrentCount", this.getCachedPreparedStatementCount());map.put("Version", this.getVersion());// 40 -map.put("LastErrorTime", this.getLastErrorTime());map.put("LastCreateErrorTime", this.getLastCreateErrorTime());map.put("CreateErrorCount", this.getCreateErrorCount());map.put("DiscardCount", this.getDiscardCount());map.put("ExecuteQueryCount", this.getExecuteQueryCount());map.put("ExecuteUpdateCount", this.getExecuteUpdateCount());return map;} catch (JMException ex) {throw new IllegalStateException("getStatData error", ex);}}

DruidDataSource的getStatDataForMBean定义了给jmx的所有监控项

DruidDataSourceUtils

com/alibaba/druid/util/DruidDataSourceUtils.java

    public static Map<String, Object> getStatDataForMBean(Object druidDataSource) {if (druidDataSource.getClass() == DruidDataSource.class) {return ((DruidDataSource) druidDataSource).getStatDataForMBean();}try {Method method = druidDataSource.getClass().getMethod("getStatDataForMBean");Object obj = method.invoke(druidDataSource);return (Map<String, Object>) obj;} catch (Exception e) {LOG.error("getStatDataForMBean error", e);return null;}}

DruidDataSourceUtils提供了静态方法用于获取监控项

小结

DruidDataSource的init方法会执行registerMbean,把自身注册到mbeanServer,它实现了DruidDataSourceMBean接口;而DruidDataSourceUtils提供了静态方法用于获取监控项,它使用的是DruidDataSource的getStatDataForMBean方法(貌似没直接给到jmx),可以利用该方法把指标暴露给micrometer,之后就可以利用micrometer的集成能力输出到各个监控平台。

相关文章:

聊聊druid连接池的监控

序 本文主要研究一下druid连接池的监控 init com/alibaba/druid/pool/DruidDataSource.java public void init() throws SQLException {//......registerMbean();//...... }DruidDataSource的init方法会执行registerMbean registerMbean com/alibaba/druid/pool/DruidData…...

CentOS 7 安装 Docker 的详细步骤

文章目录 Docker简介1.更新2.安装必要的软件包3.添加Docker仓库4.安装5.安装后的一些常规设置及常用的命令5.1 启动 Docker5.2 Docker 在系统启动时自动运行5.3 运行一个 Hello World 镜像5.4 查看docker运行状态5.5 docker ps5.6 查看docker版本 6.安装种常见的错误错误1:yum-…...

竞赛 基于深度学习的动物识别 - 卷积神经网络 机器视觉 图像识别

文章目录 0 前言1 背景2 算法原理2.1 动物识别方法概况2.2 常用的网络模型2.2.1 B-CNN2.2.2 SSD 3 SSD动物目标检测流程4 实现效果5 部分相关代码5.1 数据预处理5.2 构建卷积神经网络5.3 tensorflow计算图可视化5.4 网络模型训练5.5 对猫狗图像进行2分类 6 最后 0 前言 &#…...

数据结构之【泛型】

泛型&#xff1a;定义阶段不明确具体类型&#xff0c;产生对象时明确具体类型。 //Object是Java中的最高参数统一化&#xff0c;能够接受所有的引用类型&#xff1b; //有了包装类的自动拆装箱之后&#xff0c;Object还能够接收基本类型数值&#xff08;自动装箱&#xff09; …...

华为ac无线侧命令行配置思路和步骤

无线侧配置思路&#xff1a; Ap和ac在同一个广播域内&#xff0c;不用配置 option 43 source 源ip回包哪个模式都得配置 Cli配置业务模版流程&#xff1a; 1、 AC控制器上全局配置capwap回包接口地址 1、配置ssid&#xff1a;wifi名称 2、配置安全模版&#xff1a;用户连接密码…...

十六)Stable Diffusion教程:出图流程化

今天说一个流程化出图的案例&#xff0c;适用很多方面。 1、得到线稿&#xff0c;自己画或者图生图加线稿lora出线稿&#xff1b;如果想sd出图调整参数不那么频繁细致&#xff0c;则线稿的素描关系、层次、精深要表现出来&#xff0c;表现清楚。 2、文生图&#xff0c;seed随机…...

SpringBoot全局异常处理源码

SpringBoot全局异常处理源码 一、SpringMVC执行流程二、SpringBoot源码跟踪三、自定义优雅的全局异常处理脚手架starter自定义异常国际化引入封装基础异常封装基础异常扫描器&#xff0c;并注册到ExceptionHandler中项目分享以及改进点 一、SpringMVC执行流程 今天这里叙述的全…...

设计模式——7. 装饰者模式

1. 说明 装饰者模式(Decorator Pattern)是一种结构型设计模式,它允许你在不改变对象接口的前提下,动态地将新行为附加到对象上。这种模式是通过创建一个包装(或装饰)对象,将要被装饰的对象包裹起来,从而实现对原有对象功能的增强和扩展。 装饰者模式的主要特点包括:…...

安卓玩机-----反编译apk 修改apk 去广告 去弹窗等操作中的一些常识

安卓机型app的编译与反编译 apk文件的简单说明与解析 -安卓修改apk apk的组成和编译 一 电脑端几种反编译apk工具操作步骤解析 前面几个博文有说明关于反编译apk和apk架构等有些常识.今天对以上做个补充。初学者记住一点。对于一个apk文件使用压缩软件7zip打开可以查看到文件…...

Hoeffing不等式

在李航老师的统计学习方法&#xff08;第一版中&#xff09; H o e f f i n g 不等式 Hoeffing不等式 Hoeffing不等式是这样子给出的 设 X 1 , X 2 , . . . , X N X_1,X_2,...,X_N X1​,X2​,...,XN​是独立随机变量&#xff0c;且 X i ∈ [ a i , b i ] , i 1 , 2 , . . . ,…...

ffmpeg解复用指定pid转推udp

命令 ffmpeg -re -i udp://224.2.2.2:4003?fifo_size1024000 -map #5001 -acodec copy -flush_packets 1 -f mpegts udp://192.168.2.62:5161 ffmpeg -re -i udp://224.2.2.2:4003?fifo_size1024000 -map #5001 -acodec copy -flush_packets 1 -f mpegts udp://192.16…...

Vue组件通信方式

1.props通信 1.1在 Vue 2 中使用 props 通信 注意:props传递的数据是只读的,子组件修改,不会影响父组件 1.1.1.定义 props 在子组件中使用 props 选项来定义要接收的属性 // 子组件 <script> export default {props: {message: String} } </script>1.1.2.传递…...

redis-设置从节点

节点结构 节点配置文件 主节点 不变 6380节点 port 6380 slaveof 127.0.0.1 63796381节点 port 6381 slaveof 127.0.0.1 6380启动 指定配置文件的方式启动 D:\jiqun\redis\Redis-6380>redis-server.exe redis.windows.conf启动时&#xff0c;会触发同步数据命令 主节点…...

k8s-实战——基于nfs实现动态存储

部署nfs服务 基于Centos7.9版本创建动态存储注意k8s版本应低于v1.24版本高k8s版本ServiceAccount需要手动创建secrets并关联相关sa部署流程 创建NFS共享服务、采用单独的节点用于nfs服务独占安装nfs-utils和rpcbindnfs客户端和服务端都安装nfs-utils包通过部署化脚本安装k8s集群…...

【广州华锐互动】鱼类授精繁殖VR虚拟仿真实训系统

随着科技的不断发展&#xff0c;虚拟现实技术在各个领域的应用越来越广泛。在养殖业中&#xff0c;VR技术可以帮助养殖户进行家鱼授精实操演练&#xff0c;提高养殖效率和繁殖成功率。本文将介绍利用VR开展家鱼授精实操演练的方法和应用。 首先&#xff0c;我们需要了解家鱼授精…...

RocketMQ Promethus Exporter

介绍​ Rocketmq-exporter 是用于监控 RocketMQ broker 端和客户端所有相关指标的系统&#xff0c;通过 mqAdmin 从 broker 端获取指标值后封装成 87 个 cache。 警告 过去版本曾是 87 个 concurrentHashMap&#xff0c;由于 Map 不会删除过期指标&#xff0c;所以一旦有 la…...

Kafka收发消息核心参数详解

文章目录 1、从基础的客户端说起1.1、消息发送者主流程1.2、消息消费者主流程 2、从客户端属性来梳理客户端工作机制2.1、消费者分组消费机制 1、从基础的客户端说起 Kafka提供了非常简单的客户端API。只需要引入一个Maven依赖即可&#xff1a; <dependency><groupId…...

Springboot中Aop的使用

Springboot中使用拦截器、过滤器、监听器-CSDN博客 相比较于拦截器&#xff0c;Spring 的aop则功能更强大&#xff0c;封装的更细致&#xff0c;需要单独引用 jar包。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-b…...

创建vue3项目、链式调用、setup函数、ref函数、reactive函数、计算和监听属性、vue3的生命周期、torefs的使用、vue3的setup写法

1 创建vue3项目 # 两种方式- vue-cli&#xff1a;vue脚手架---》创建vue项目---》构建vue项目--》工具链跟之前一样- vite &#xff1a;https://cn.vitejs.dev/-npm create vuelatest // 或者-npm create vitelatest一路选择即可# 运行vue3项目-vue-cli跟之前一样-vite 创建的…...

搭建好自己的PyPi服务器后怎么使用

当您成功搭建好自己的 PyPI 服务器后&#xff0c;您可以使用以下步骤来发布和使用您的包&#xff1a; 打包您的代码&#xff1a; 首先&#xff0c;将您的 Python 项目打包成一个发布包。确保您已经在项目根目录下创建了 setup.py 文件&#xff0c;并按照正确的格式填写了项目信…...

Vue3 中使用provide和reject

1、provide 和reject 可以实现一条事件线上的 父传子&#xff0c;父传孙等&#xff1b;相比较 props emits 仅限与父子传参更方便&#xff0c;相较于pinia书写更简单&#xff0c;但是需要注意使用响应式&#xff0c;如果是非响应式的会导致页面更新不及时 父组件 <templat…...

大数据flink篇之一-基础知识

一、起源 2010至2014年间&#xff0c;由柏林工业大学、柏林洪堡大学和哈索普拉特纳研究所联合发起名Stratosphere的研究项目。2014年4月&#xff0c;项目贡献给Apache基金会&#xff0c;成为孵化项目。更名为Flink2014年12月&#xff0c;成为基金会顶级项目2015年9月&#xff…...

No140.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…...

Oracle 11g_FusionOS_安装文档

同事让安装数据库&#xff0c;查询服务器信息发现操作系统是超聚变根据华为openEuler操作系统更改的自研操作系统&#xff0c;安装过程中踩坑不少&#xff0c;最后在超聚变厂商的技术支持下安装成功&#xff0c;步骤可参数该文。 一、 安装环境准备 1.1 软件下载 下载地址:…...

Linux驱动实现IO模型

在Linux系统分为内核态和用户态&#xff0c;CPU会在这两个状态之间进行切换。当进行IO操作时&#xff0c;应用程序会使用系统调用进入内核态&#xff0c;内核操作系统会准备好数据&#xff0c;把IO设备的数据加载到内核缓冲区。 然后内核操作系统会把内核缓冲区的数据从内核空…...

wsl2 更新报错问题解决记录

1、问题 win10 中安装的 wsl2&#xff0c;启动 docker desktop 时提示 wsl2 有问题&#xff1a; 于是点击推荐的地址连接到微软&#xff0c;下载 wsl2 的更新文件。之后运行&#xff0c;又报错&#xff1a; 更新被卡住。 2、解决方法 WinR 输入 cmd 打开命令行窗口&#x…...

突破算法迷宫:精选50道-算法刷题指南

前言 在计算机科学和编程领域&#xff0c;算法和数据结构是基础的概念&#xff0c;无论你是一名初学者还是有经验的开发者&#xff0c;都需要掌握它们。本文将带你深入了解一系列常见的算法和数据结构问题&#xff0c;包括二分查找、滑动窗口、链表、二叉树、TopK、设计题、动…...

玩转Mysql系列 - 第26篇:聊聊mysql如何实现分布式锁?

这是Mysql系列第26篇。 本篇我们使用mysql实现一个分布式锁。 分布式锁的功能 分布式锁使用者位于不同的机器中&#xff0c;锁获取成功之后&#xff0c;才可以对共享资源进行操作 锁具有重入的功能&#xff1a;即一个使用者可以多次获取某个锁 获取锁有超时的功能&#xff…...

linux 解压缩命令tar

Tar tar 命令的选项有很多(用 man tar 可以查看到)&#xff0c;但常用的就那么几个选项&#xff0c;下面来举例说明一下&#xff1a; tar -cf all.tar *.jpg 这条命令是将所有.jpg 的文件打成一个名为 all.tar 的包。-c 是表示产生新的包&#xff0c;-f 指 定包的文件名。 …...

OpenAI ChatGPT API 文档之 Embedding

译者注&#xff1a; Embedding 直接翻译为嵌入似乎不太恰当&#xff0c;于是问了一下 ChatGPT&#xff0c;它的回复如下&#xff1a; 在自然语言处理和机器学习领域&#xff0c;"embeddings" 是指将单词、短语或文本转换成连续向量空间的过程。这个向量空间通常被称…...

如何替换网站的图片/企业如何注册自己的网站

摘要之前我们讲了如何求梯度, 如何使用Pytorch求解梯度. 这里我们介绍梯度下降法, 用一个例子, 介绍如何优化参数.简介上一篇我们计算得到了各个系数(w1和w2)的梯度, 这一篇我们介绍梯度下降法, 来优化这些系数. 这一篇主要有以下几个部分:梯度下降法的简单介绍;手动实现梯度下…...

陕西响应式网站建设公司/网站推广优化怎样

本篇文章给大家带来的内容是关于vue和iview以及less如何实现换肤的功能(附代码)&#xff0c;有一定的参考价值&#xff0c;有需要的朋友可以参考一下&#xff0c;希望对你有所帮助。项目搭建用的vue—cli&#xff0c;css框架选择的iview1、首先安装less支持npm install --save-…...

绵阳做网站的有哪些/大型集团网站建设公司

背景 在服务器上安装了服务&#xff0c;其中有使用chromedp来进行网页截屏 在云服务器使用chromedb包需要事先安装chrome ##下载源加入到系统的源列表 sudo wget http://www.linuxidc.com/files/repo/google-chrome.list -P /etc/apt/sources.list.d/##导入谷歌软件公钥 wget…...

网页设计与网站建设期末考试试卷/最近新闻小学生摘抄

Postman作为软件测试里一款非常流行的调试工具&#xff0c;给我们提供了一个执行JavaScript脚本的环境&#xff0c;所以我们可以使用js语言编写脚本来解决一些接口自动化的问题&#xff0c;比如接口依赖、接口断言等等。Postman有Pre-RequestScript和Tests两个编写js脚本的模块…...

ui设计的工作流程/整站优化

从2015年数据统计不难发现&#xff0c;移动端已有超越PC的趋势&#xff0c;未来更多的用户将趋于使用移动设备连接互联网。因此&#xff0c;对于各位站长而言&#xff0c;死守PC端的搜索引擎优化&#xff0c;将没有出路&#xff0c;必须早日做好移动端的优化工作。特别是对于国…...

11电影网/北京自动seo

AOP是什么&#xff1f;    AOP是OOP的延续&#xff0c;Aspect Oriented Programming的缩写&#xff0c;即面向方面编程。AOP是GoF设计模式的延续&#xff0c;设计模式追求的是调用者和被调用者之间的解耦&#xff0c;AOP也是这种目标的一 种实现。    案例:在应用程序中…...