Spring framework :基于 jdk 动态代理实现连接池复用

前言

在数据库开发中,连接池是一种重要的技术手段,它可以提高数据库连接的复用性和性能。连接池的原理是在应用启动时创建一定数量的数据库连接,并将这些连接保存在一个池中,应用程序需要数据库连接时,从连接池中获取一个连接进行操作,不再频繁地创建和关闭连接。

为了更好地利用连接池并实现连接的复用,我们可以借助JDK动态代理机制来实现连接对象的自动重用。通过在动态代理中拦截连接的获取和归还操作,我们可以对连接对象进行有效地管理,确保每次使用完毕后将连接归还到连接池中,从而实现连接的复用,提高性能和效率。

接下来,我们将结合JDK动态代理机制和连接池技术,实现一个基于动态代理的连接池复用功能。

如果不了解 jdk 动态代理的,可以去回顾一下我的这篇文章: http://t.csdnimg.cn/BJnzh

一、开始学习

1、新建项目,结构如下

2、导入依赖
 <!-- spring 的核心依赖 --><dependencies><!-- https://mvnrepository.com/artifact/org.springframework/spring-context --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.23</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.4.5</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency></dependencies>
 3、在 pool 包下新建三个类,ConnectionInvocationHandler、ConnectionPool、ConnUtils

ConnUtils 类


@Slf4j
public class ConnUtils {public static Connection getConnection(String url, String name, String password) {try {return DriverManager.getConnection(url, name, password);} catch (SQLException e) {throw new RuntimeException("connection erro", e);}}}

主要是用来获取数据库连接的工具类

ConnectionPool (连接池)


@Setter
public class ConnectionPool {/*** 连接池(存放连接的集合)*/private LinkedList<Connection> pool = new LinkedList<>();/*** 连接属性*/private String url;private String name;private String password;/*** 池大小*/private Integer poolSize;/*** 在构造方法中初始化连接池大小**/public void init() throws SQLException {for (int i = 0; i < poolSize; i++) {// 1、从数据库获取连接对象Connection connection = ConnUtils.getConnection(url,name,password);// 2、对连接对象创建代理connection = createProxy(connection);// 3、将连接对象返回连接池中connection.close();}}/*** 为连接对象创建代理** @param connection* @return*/private Connection createProxy(Connection connection) {// 创建回调处理器ConnectionInvocationHandler connectionInvocationHandler = new ConnectionInvocationHandler(connection,pool);// 获取连接对象的所有接口Class<?>[] interfaces = new Class[]{Connection.class};// 获取类加载器ClassLoader loader = ConnectionPool.class.getClassLoader();// 创建代理connection = (Connection) Proxy.newProxyInstance(loader,interfaces,connectionInvocationHandler);return connection;}/*** 从池里获取代理连接** @return*/public Connection getConnection() {return pool.removeFirst();}/*** 查看连接池的大小* @return*/public int size(){return pool.size();}}

这个类是一个连接池的实现,用于管理数据库连接对象。连接池的作用是在应用程序初始化时创建一定数量的数据库连接,并将这些连接保存在连接池中,当应用程序需要使用数据库连接时,可以从连接池中获取连接,使用完毕后将连接放回连接池,以便其他线程或请求继续使用。

连接池可以提高数据库的性能和效率,主要有以下几个方面的作用:

  1. 连接的复用:连接池中已经创建好的连接可以被反复利用,避免频繁地创建和关闭连接,从而减少了连接的创建和销毁开销。

  2. 连接的管理:连接池可以对连接进行有效的管理,包括连接的创建、销毁、状态的监控等,确保连接的可用性和稳定性。

  3. 连接的限制:连接池可以设置最大连接数,防止因为连接过多导致数据库负载过高或内存资源耗尽,从而提高系统的稳定性和安全性。

通过使用连接池,可以减少数据库连接的创建和销毁次数,提高数据库访问的效率,同时能够更好地管理和控制数据库连接的使用,确保系统的性能和可靠性。

 ConnectionInvocationHandler类


public class ConnectionInvocationHandler implements InvocationHandler {/*** 目标对象(被代理对象)*/private Connection connection;/*** 连接池*/private LinkedList<Connection> pool;public ConnectionInvocationHandler(Connection connection, LinkedList<Connection> pool) {this.connection = connection;this.pool = pool;}public ConnectionInvocationHandler(Connection connection) {this.connection = connection;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 如果当前调用的是 Connection 的 close 方法则将它放回到池中if ("close".equals(method.getName())) {// 从池的尾部放回去// 注意:这里放回池中的必须是代理对象,而不是目标 Connectionpool.addLast((Connection) proxy);return null;} else {// 除 close 以外的其他方法则正常调用目标对象的行为return method.invoke(connection, args);}}
}

 这是一个代理类,实现了InvocationHandler接口,用于代理连接对象。主要作用是拦截连接对象的close方法,并将其放回连接池中,以便其他线程或请求继续使用。

在代理对象调用close方法时,ConnectionInvocationHandler会将代理对象(即当前正在被使用的连接)放回到连接池中,而不是直接关闭代理对象。这样可以确保连接池中的连接资源得到充分利用,提高应用程序的性能。

在代理对象调用除close以外的方法时,ConnectionInvocationHandler会将方法调用转发给目标对象(即被代理的连接对象),并返回方法的结果。这样可以保证应用程序的正常逻辑,对于使用者来说,无需关心连接对象被代理的具体实现,只需要按照正常的方式使用连接对象即可。

总之,ConnectionInvocationHandler是整个连接池的核心之一,它负责管理连接对象的生命周期,确保连接对象能够得到充分利用和正确释放,保障应用程序的性能和可靠性。

4、在 resources 包下新建一个 db.properties 文件
url = jdbc:mysql://localhost:3306/psm
name = root
password = 123456
poolSize = 5
5、在 config 包下新建一个 AppConfig 类

@Configuration
@PropertySource("classpath:db.properties")
@Slf4j
public class AppConfig {@Value("${url}")private String url;@Value("${name}")private String userName;@Value("${password}")private String password;@Value("${poolSize}")private Integer poolSize;/*** 装配连接池** @return*/@Beanpublic ConnectionPool connectionPool() throws SQLException {log.info("url:" + url);log.info("name:" + userName);log.info("password:" + password);log.info("size:" + poolSize);// 创建连接池并设置相关的属性ConnectionPool pool = new ConnectionPool();pool.setUrl(url);pool.setName(userName);pool.setPassword(password);pool.setPoolSize(poolSize);// 初始化连接池pool.init();return pool;}}

这是一个用于配置连接池的类。通过@Configuration注解将它标记为一个配置类,并使用@PropertySource注解指定了属性文件的位置。

在该类中,使用了@Value注解来注入属性值。根据属性文件中的配置,注入了urlnamepasswordpoolSize等属性值,分别表示数据库的URL、用户名、密码和连接池的大小。

connectionPool()方法中,创建了一个ConnectionPool对象,并通过setter方法设置了相关属性的值。然后调用init()方法初始化连接池,使其预先创建一定数量的数据库连接。

最后将创建好的连接池对象返回,以供其他组件或类进行使用。

整个配置类的作用是将属性文件中的配置值注入到连接池对象中,并初始化连接池,以方便应用程序使用数据库连接。

6、测试

@Slf4j
public class Main {public static void main(String[] args) throws SQLException {ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);// 从容器中获取连接池ConnectionPool connectionPool = context.getBean(ConnectionPool.class);log.info("连接数:" + connectionPool.size());Connection conn1 = connectionPool.getConnection();Connection conn2 = connectionPool.getConnection();log.info("连接数:" + connectionPool.size());conn1.close();log.info("连接数:" + connectionPool.size());}
}

运行结果

二、 这个案例是干嘛的

这个案例主要用于配置和初始化连接池,以便在应用程序中高效地管理数据库连接。它具有以下几个作用:

  1. 抽象化数据库连接:通过使用连接池,应用程序可以从简单的直接获取和释放数据库连接的方式转变为通过连接池来获取和释放连接。连接池负责维护一定数量的数据库连接,并在需要时提供连接给应用程序使用。这样可以避免频繁地创建和关闭连接,提高数据库操作的效率。

  2. 提高性能和资源利用率:连接池可以预先创建一定数量的数据库连接,并将其保存在池中。当应用程序需要数据库连接时,可以从连接池中获取连接,而不是每次都创建一个新的连接。这样可以避免了频繁地创建和销毁连接的开销,提高了数据库操作的性能和资源的利用率。

  3. 简化配置和管理:通过将连接池的配置信息(如URL、用户名、密码、连接池大小等)放入属性文件中,并通过配置类进行加载和注入,可以方便地进行配置和管理。这使得连接池的配置可以与应用程序的其他部分分离,易于维护和修改。

总之,这个案例提供了一种在应用程序中配置和初始化连接池的方式,帮助管理数据库连接,提高数据库操作的性能和资源利用率,同时简化了配置和管理的过程。

三、总结

这只是一个利用 jdk 动态代理实现的一个简单的连接池的案例,仅仅知识实现了连接池的复用,连接池中还有很多的 API 方法。

四、gitee 案例

地址:ch17/src/main/java/edu/nf/ch17/pool · qiuqiu/spring-framework - 码云 - 开源中国 (gitee.com)

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

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

相关文章

Oracle数据库修改序列,Oracle中的主键值和序列中的值对应不上时的处理方式

select max(stu.id) maxid from student stu; //查询student表中id的最大值select XXX_SEQ.nextval from dual; //查询student表中id对应序列XXX_SEQ的下一个值alter sequence XXX_SEQ increment by 1000; //将序列XXX_SEQ步长改为1000&#xff0c;对应 student表中id的最大值s…

全波形反演培训的思考与总结

一. InversionNet: 最简单的端到端DL_FWI 1. 网络结构&#xff1a; 图1 构建了一个具有编码器-解码器结构的卷积神经网络&#xff0c;根据地震波动数据模拟地下速度结构。编码器主要由卷积层构建&#xff0c;它从输入地震数据中提取高级特征并将其压缩为单个高维向量。解码器然…

推荐《机动战士高达SEED DESTINY》

《机动战士高达SEED DESTINY》是《机动战士高达SEED》的续集&#xff0c;于日本时间2004年10月9日—2005年10月1日每周六下午六点在每日放送、TBS电视台系列电视台播出&#xff0c;全50话。 [1] 台湾版权由博英社取得&#xff0c;并于2005年10月8日起由中国电视公司在每周六播…

面试题-React(十四):什么是高阶组件(HOC)及其作用

一、高阶组件的概念 高阶组件&#xff08;HOC&#xff09;是一种函数&#xff0c;接受一个组件作为参数&#xff0c;并返回一个新的组件。这个新的组件具有一些增强的特性或功能。简而言之&#xff0c;高阶组件就是用来“包装”其他组件的函数。 二、高阶组件的作用 高阶组件…

float、double类型的转化和判断为零问题

1、将字符串转化为float、double 浮点数在内存中的存储机制和整形数据不同&#xff0c;有舍入误差&#xff0c;在计算机中用近似表示任意某个实数。具体来说&#xff0c;这个数由一个整数或定点数&#xff08;即尾数&#xff09;乘以某个基数&#xff08;计算机中通常是2&…

uni-app:js实现数组中的相关处理

一、查询数组中&#xff0c;某一项中的某个数据为指定值的项&#xff08;find() 方法&#xff09; 使用分析 使用数组的 find() 方法来查询 id 为 0 的那一项数据。这个方法会返回满足条件的第一个元素&#xff0c;如果找不到符合条件的元素&#xff0c;则返回 undefined。使用…

操作系统【OS】微内核

基本概念 微内核结构将操作系统划分为两大部分&#xff1a;微内核多个服务器微内核包含&#xff1a; 与硬件处理紧密相关的部分一些较基本的功能客户和服务器间的通信客户与服务器之间是借助微内核提供的消息传递机制来实现交互的 基本功能 进程管理 进程的通信、切换、调度…

Ubuntu - 安装 、配置 Redis 远程连接和密码

在Ubuntu上安装Redis 要在Ubuntu上安装Redis&#xff0c;需要按照以下步骤操作&#xff1a; 打开终端&#xff1a;使用CtrlAltT快捷键或在应用程序中搜索终端来打开终端。 更新系统包列表&#xff1a;在终端中运行以下命令&#xff0c;以确保系统中的软件包列表是最新的&…

天鹰340亿(AquilaChat2-34B-16K)本地部署的解决方案

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

嵌入式软件开发笔试面试

C语言部分&#xff1a; 1.gcc的四步编译过程 1.预处理 展开头文件&#xff0c;删除注释、空行等无用内容&#xff0c;替换宏定义。 gcc -E hello.c -o hello.i 2.编译 检查语法错误&#xff0c;如果有错则报错&#xff0c;没有错误则生成汇编文件。 gcc -S hello.i -o h…

ArGIS Engine专题(14)之GP模型根据导入范围与地图服务相交实现叠置分析

一、结果预览 二、需求简介 前端系统开发时,可能遇到如下场景,如客户给出一个图斑范围,导入到系统中后,需要判断图斑是否与耕地红线等地图服务存在叠加,叠加的面积有多少。虽然arcgis api中提供了相交inserect接口,但只是针对图形几何之间的相交,如何要使用该接口,则需…

LSTM-Attention单维时间序列预测研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

LC-2316. 统计无向图中无法互相到达点对数(DFS、并查集)

2316. 统计无向图中无法互相到达点对数 中等 给你一个整数 n &#xff0c;表示一张 无向图 中有 n 个节点&#xff0c;编号为 0 到 n - 1 。同时给你一个二维整数数组 edges &#xff0c;其中 edges[i] [ai, bi] 表示节点 ai 和 bi 之间有一条 无向 边。 请你返回 无法互相…

【LeetCode】57. 插入区间

1 问题 给你一个 无重叠的 &#xff0c;按照区间起始端点排序的区间列表。 在列表中插入一个新的区间&#xff0c;你需要确保列表中的区间仍然有序且不重叠&#xff08;如果有必要的话&#xff0c;可以合并区间&#xff09;。 示例 1&#xff1a; 输入&#xff1a;interval…

第17章 MQ(二)

17.11 RabbitMQ如何保证消息的顺序性 难度:★★ 重点:★★★ 白话解析 其实RabbitMQ是一个先进先出的队列,只要消息进入到队列之后那肯定是顺序的,其实这道题问的点就是在消息进队列之前和出队列之后如何保证顺序性。 1、要保证消息进队列的顺序性实际只需要保证生产者只…

Matlab遗传算法工具箱——一个例子搞懂遗传算法

解决问题 我们一般使用遗传算法是用来处理最优解问题的&#xff0c;下面是一个最优解问题的例子 打开遗传算法工具箱 ①在Matlab界面找到应用程序选项&#xff0c;点击应用程序(英文版的Matlab可以点击App选项) ②找到Optimization工具箱&#xff0c;点击打开 创建所需要…

【计算机网络】OSI参考模型中非端-端层(物理层、数据链路层、网络层)功能介绍

系列文章目录 什么是计算机网络&#xff1f; 什么是网络协议&#xff1f; 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能&#xff08;1&#xff09;——速率、带宽、延迟 计算机网络性能&#xff08;2&#xff09;…

jdk对linux cgroup v2容器化环境识别情况

Linux各发行版将cgroups v2作为默认的情况如下&#xff1a; Container-Optimized OS&#xff08;从 M97 开始&#xff09;Ubuntu&#xff08;从 21.10 开始&#xff0c;推荐 22.04&#xff09;Debian GNU/Linux&#xff08;从 Debian 11 Bullseye 开始&#xff09;Fedora&…

GB28181学习(九)——校时

要求 联网内设备支持基于SIP方式或NTP方式的网络校时功能&#xff0c;标准时间为北京时间&#xff1b;系统运行时可根据配置使用具体校时方式&#xff1b; 流程 SIP校时在注册过程中完成&#xff0c;流程同注册和注销流程&#xff1b;在注册成功情况下&#xff0c;注册流程的…

连续/离散的控制系统阶跃测试(包括MATLAB里的step()函数)

阶跃测试 只要是连续时间系统&#xff0c;无论是传递函数还是连续状态空间形式的模型&#xff0c;直接可以用**step()**做阶跃测试&#xff1b;但是对于离散系统而言&#xff0c;不能用step()函数&#xff0c;可以自行编写代码&#xff0c;如下。 1、离散系统&#xff1a;x(k…