GenericKeyedObjectPool
通用池化框架commons-pool2实践,其中提到了可以池化一个对象和一组对象,一个对象用到了GenericObjectPool
这个类,一组对象用到了GenericKeyedObjectPool
这个类。顾名思义,键值对象池。就是通过一个key对应一个对象类型来组合对象池,其本质上就是一个Map
,key
是自定义,value
就是org.apache.commons.pool2.ObjectPool
,而但对象池化类GenericObjectPool
也是实现了这个接口。
注意:
Map
用的ConcurrentHashMap
,是线程安全的。- 获取和回收太频繁,会遇到性能问题。
1. 依赖
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.7.0</version>
</dependency>
2. 配置
例如:配置多sftp主机连接
sftp:
hosts:
remote-1:
host: 127.0.0.1
port: 22
username: root
password: 1234
remote-2:
host: 127.0.0.2
port: 22
username: root
password: 1234
3. 连接对象类
- 被对象池管理的对象
- 可以想象为一个连接,创建复杂,比如数据库或者redis或者socket之类的对象
@Data
@ConfigurationProperties("sftp")
public class SftpProperties {
private String host = "localhost";
private int port = 22;
private String username;
private String password = "";
private LinkedHashMap<String, SftpProperties> hosts;
...
}
4. 对象池工厂
然后就是池化工厂类,这个类需要定义key
和value
的类型,然后就是照葫芦画瓢。继承BaseKeyedPooledObjectFactory<K, V>类,并重写create()、wrap()等方法
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
/**
* 对象池工厂
*/
private static class KeyedPooledClientFactory extends BaseKeyedPooledObjectFactory<String, SftpClient> {
private final Map<String, SftpProperties> SftpPropertiesMap;
private KeyedPooledClientFactory(Map<String, SftpProperties> SftpPropertiesMap) {
this.SftpPropertiesMap = SftpPropertiesMap;
}
/**
* 根据当前key(remote-1、remote-2)得到的配置信息,创建sftp客户端
*/
public SftpClient create(String key) {
//SftpClient构造中,根据key拿到对应的主机配置后初始化sftp连接对象
return new SftpClient(SftpPropertiesMap.get(key));
}
/**
* common-pool2 中创建了 DefaultPooledObject 对象对对象池中对象进行的包装。
* 将我们自定义的对象放置到这个包装中,工具会统计对象的状态、创建时间、更新时间、返回时间、出借时间、使用时间等等信息进行统计
*/
public PooledObject<SftpClient> wrap(SftpClient sftpClient) {
return new DefaultPooledObject<>(sftpClient);
}
/**
* 校验对象是否可用
*/
public boolean validateObject(String key, PooledObject<SftpClient> p) {
return p.getObject().test();
}
/**
* 销毁对象
*/
public void destroyObject(String key, PooledObject<SftpClient> p) {
p.getObject().disconnect();
}
}
com.funtester.funpool.KeyPoolFactory#destroyObject
方法并不是必需的,如果池化的对象除了内存以外不需要额外的资源释放,就不用重写这个方法了。还有一种情况就是对象信息需要清除,比如org.apache.http.client.methods.HttpGet
,需要把请求地址和请求头等信息清除,这个需要跟业务需求保持一致。不一定是全都清除。
5. 使用
public class SftpPool {
//池化一组对象用GenericKeyedObjectPool类
private GenericKeyedObjectPool<String, SftpClient> internalKeyedPool;
public SftpPool(Map<String, SftpProperties> SftpPropertiesMap, PoolProperties poolProperties) {
this.internalKeyedPool = new GenericKeyedObjectPool<>(SftpPropertiesMap, getKeyedPoolConfig(poolProperties));
}
/**
* 根据key,在池中借对象
*/
public SftpClient borrowObject(String key) {
try {
internalKeyedPool.borrowObject(key);
} catch (Exception e) {
throw new PoolException("COULD_NOT_GET_A_RESOURCE_FROM_THE_POOL");
}
}
/**
* 根据key,往池中归还对象
*/
public void returnObject(String key, SftpClient sftpClient) {
try {
internalKeyedPool.returnObject(key, sftpClient);
} catch (Exception e) {
throw new PoolException("COULD_NOT_GET_A_RESOURCE_FROM_THE_POOL");
}
...
}
转自:
https://www.cnblogs.com/lihw/p/17391562.html