对象池及其学习common-pool2

文章目录
  1. 1. 对象池的其他使用场景
  2. 2. 常见问题及解决方案
    1. 2.1. 1. 对象泄漏
    2. 2.2. 2. 对象池配置不当
    3. 2.3. 3. 对象的有效性
  3. 3.
  4. 4. 如何使用 commons-pool2
    1. 4.1. 创建对象池
    2. 4.2. 配置对象池
    3. 4.3. 处理池中的对象

关于使用 Apache 下的 commons-pools 可以实现对象的池化对于经常需要重复使用不想重复创建的对象,同时提供自动调用和维护的方法来维持对象的存活,它通过使用对象池来提高性能和资源利用率,特别是在需要频繁创建和销毁对象的场景中。

对于当前很多需要使用一些 SDK 来对接的一些服务来说就很方便对于对象存储的 SDK 来说其实对于的 SDK 提供了保活,只需要根据对接的服务来调用已经创建的客户端实例就可以,但是本次项目需要对接 SFTP,FTP的数据源,都是偏底层的服务,在使用过程中,需要使用客户端来创建 session 来进行通讯,而且创建 session 的过程。s

相对较为耗时,为了提高整体系统性能,我们需要使用对象池来管理这些客户端实例,这样一来,我们可以显著减少客户端实例的创建和销毁次数,从而提高系统的响应速度和资源利用率。

对象池的其他使用场景

除了管理 SFTP、FTP 等底层服务的客户端实例,对象池在以下场景中也非常有用:

  1. 数据库连接池:通过池化数据库连接,可以减少连接建立和关闭的开销,提高数据库操作的性能。
  2. 线程池:线程池用于管理工作线程,避免频繁创建和销毁线程,从而提高并发处理能力。
  3. 缓存对象池:在高频率访问的场景中,通过池化缓存对象可以减少内存分配和垃圾回收的压力。
  4. 网络连接池:池化网络连接可以提高网络通信的效率,特别是在高并发访问的场景中。

常见问题及解决方案

虽然对象池可以显著提高性能,但在使用过程中也可能遇到一些问题:

1. 对象泄漏

如果某些对象没有归还到池中,就会导致对象泄漏,从而影响池的可用性。解决方法是确保在任何情况下都能正确归还对象,最好使用 try-finally 或者 try-with-resources 语句来管理对象的借用和归还。

2. 对象池配置不当

不合理的池配置可能会导致资源浪费或不足。例如,池的最大对象数设置过大可能会占用过多的内存,而设置过小则可能无法满足高并发需求。解决方法是根据实际需求和性能测试结果来调整配置参数。

3. 对象的有效性

池化的对象在借用和归还之间可能会失效,例如网络连接中断等。解决方法是实现对象的验证逻辑,在每次借用对象时进行有效性检查,如果对象无效则重新创建。

如何使用 commons-pool2

要使用 commons-pool2,首先需要在项目中添加相关的依赖。对于使用 Maven 的项目,可以在 pom.xml 文件中添加以下依赖项:

1
2
3
4
5
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.11.1</version>
</dependency>

创建对象池

接下来,需要创建一个对象池。以下是一个简单的示例,展示了如何创建一个字符串对象池:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

class StringFactory implements PooledObjectFactory<String> {

@Override
public PooledObject<String> makeObject() {
return new DefaultPooledObject<>(new String("Pooled String"));
}

@Override
public void destroyObject(PooledObject<String> p) {
// No specific destruction needed for String
}

@Override
public boolean validateObject(PooledObject<String> p) {
return p.getObject() != null;
}

@Override
public void activateObject(PooledObject<String> p) {
// No activation needed for String
}

@Override
public void passivateObject(PooledObject<String> p) {
// No passivation needed for String
}
}

public class PoolExample {
public static void main(String[] args) throws Exception {
GenericObjectPoolConfig<String> config = new GenericObjectPoolConfig<>();
config.setMaxTotal(10); // 设置池中最多可存在的对象数
GenericObjectPool<String> pool = new GenericObjectPool<>(new StringFactory(), config);

try {
String pooledString = pool.borrowObject();
System.out.println(pooledString);
pool.returnObject(pooledString);
} finally {
pool.close();
}
}
}

配置对象池

commons-pool2 提供了多种配置选项,可以根据具体需求进行调整。例如,可以设置池中对象的最大数目、最小空闲数目、最大空闲数目、对象的最大存活时间等。

1
2
3
4
5
GenericObjectPoolConfig<String> config = new GenericObjectPoolConfig<>();
config.setMaxTotal(10);
config.setMinIdle(2);
config.setMaxIdle(5);
config.setMaxWaitMillis(3000); // 最大等待时间

处理池中的对象

从对象池中借用和归还对象时,应该始终使用 borrowObjectreturnObject 方法。这有助于确保对象的正确管理,并避免资源泄漏。

1
2
3
String pooledString = pool.borrowObject();
// 使用对象
pool.returnObject(pooledString);

通过合理配置和使用 commons-pool2,可以显著提高应用程序的性能和资源利用率,特别是在高并发和频繁对象创建的场景中。

ftp 的操作示例: https://commons.apache.org/proper/commons-net/apidocs/org/apache/commons/net/ftp/FTPClient.html,

sftp使用jsch 来链接 首先

JSch jsch = new JSch();
Session session = jsch.getSession(username, host, port);
session.setPassword(password);
session.setConfig(“StrictHostKeyChecking”, “no”);
session.connect();

ChannelSftp channelSftp = null;

Channel channel = session.openChannel(“sftp”);
channel.connect();
channelSftp = (ChannelSftp) channel;

return channelSftp;

Tips:注意事项

  • ftpclient的客户端底层是利用 socket 来通讯的,所以如果读取文件流需要调用 completePendingCommand()
  • sftp我们需要池化的是 session 每次下载文件的时候需要重新创建 session.