我发现org.apache.commons.pool非常有用且健壮,但没有充分记录。 因此,我将在这里帮助您解释如何使用Apache KeyedObjectPool 。 什么是KeyedObjectPool ? 它是一个映射,其中包含多种类型的实例池。 可以使用任意键访问每种类型。 在此示例中,我将创建一个JSch ssh连接池,并将使用一个名为ServerDetails的简单getter setter对象作为键。 基本上,对于每个服务器,我希望有10个可重用的ssh连接池。 因此,首先要做的是创建一个Sessionfactory,一个负责创建要存储在池中的实际对象的类。 在我们的示例中,这将是ssh连接。
Sessionfactory需要扩展BaseKeyedPoolableObjectFactory <K,V>,其中K
是此池中键的类型, V
是此池中保存的对象的类型。 All you need to do is implement the
makeObject方法, All you need to do is implement the
方法需要在池中实际创建对象,而destroyObject显然需要在释放对象并将其放回池中时实现代码。
package org.grep4j.core.command.linux;
import org.apache.commons.pool.BaseKeyedPoolableObjectFactory;
import org.grep4j.core.model.ServerDetails;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UserInfo;
/**
* This class is used to handle ssh Session inside the pool.
*
* @author Marco Castigliego
*
*/
public class SessionFactory extends BaseKeyedPoolableObjectFactory<ServerDetails, Session> {
/**
* This creates a Session if not already present in the pool.
*/
@Override
public Session makeObject(ServerDetails serverDetails) throws Exception {
Session session = null;
try {
JSch jsch = new JSch();
session = jsch.getSession(serverDetails.getUser(), serverDetails.getHost(), serverDetails.getPort());
session.setConfig('StrictHostKeyChecking', 'no'); //
UserInfo userInfo = new JschUserInfo(serverDetails.getUser(), serverDetails.getPassword());
session.setUserInfo(userInfo);
session.setTimeout(60000);
session.setPassword(serverDetails.getPassword());
session.connect();
} catch (Exception e) {
throw new RuntimeException(
'ERROR: Unrecoverable error when trying to connect to serverDetails : ' + serverDetails, e);
}
return session;
}
/**
* This is called when closing the pool object
*/
@Override
public void destroyObject(ServerDetails serverDetails, Session session) {
session.disconnect();
}
}
您需要做的第二件事是创建实际的密钥池对象。 在我们的示例中,我们创建一个拥有StackKeyedObjectPool的单例。 数字10是池中“睡眠”实例数量的上限。 如果11个客户端尝试为同一服务器获取ssh连接,第11个客户端将等待,直到前10个客户端之一释放其连接。
package org.grep4j.core.command.linux;
import org.apache.commons.pool.KeyedObjectPool;
import org.apache.commons.pool.impl.StackKeyedObjectPool;
import org.grep4j.core.model.ServerDetails;
import com.jcraft.jsch.Session;
/**
* Pool controller. This class exposes the org.apache.commons.pool.KeyedObjectPool class.
*
* @author Marco Castigliego
*
*/
public class StackSessionPool {
private KeyedObjectPool<ServerDetails, Session> pool;
private static class SingletonHolder {
public static final StackSessionPool INSTANCE = new StackSessionPool();
}
public static StackSessionPool getInstance() {
return SingletonHolder.INSTANCE;
}
private StackSessionPool()
{
startPool();
}
/**
*
* @return the org.apache.commons.pool.KeyedObjectPool class
*/
public KeyedObjectPool<ServerDetails, Session> getPool() {
return pool;
}
/**
*
* @return the org.apache.commons.pool.KeyedObjectPool class
*/
public void startPool() {
pool = new StackKeyedObjectPool<ServerDetails, Session>(new SessionFactory(), 10);
}
}
如何使用它,简单明了。 要从池中获取ssh连接,我们只需要调用:
StackSessionPool.getInstance().getPool().borrowObject(serverDetails)
其中,serverDetails是我们的关键(我们希望每个服务器有一个ssh连接池)。
当不再需要连接时,我们使用以下命令将其放回池中:
StackSessionPool.getInstance().getPool().returnObject(serverDetails, session);
package org.grep4j.core.command.linux;
import org.grep4j.core.command.ExecutableCommand;
import org.grep4j.core.model.ServerDetails;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.Session;
/**
* The SshCommandExecutor uses the net.schmizz.sshj library to execute remote
* commands.
*
* <ol>
* <li>Establish a connection using the credential in the {@link serverDetails}</li>
* <li>Opens a session channel</li>
* <li>Execute a command on the session</li>
* <li>Closes the session</li>
* <li>Disconnects</li>
* </ol>
*
* @author Marco Castigliego
*
*/
public class JschCommandExecutor extends CommandExecutor {
public JschCommandExecutor(ServerDetails serverDetails) {
super(serverDetails);
}
@Override
public CommandExecutor execute(ExecutableCommand command) {
Session session = null;
Channel channel = null;
try {
session = StackSessionPool.getInstance().getPool()
.borrowObject(serverDetails);
//...do stuff
} catch (Exception e) {
throw new RuntimeException(
'ERROR: Unrecoverable error when performing remote command '
+ e.getMessage(), e);
} finally {
if (null != channel && channel.isConnected()) {
channel.disconnect();
}
if (null != session) {
try {
StackSessionPool.getInstance().getPool()
.returnObject(serverDetails, session);
} catch (Exception e) {
e.printStackTrace();
}
}
}
return this;
}
}
请记住,当您不再需要使用PoolSessionPool.getInstance()。getPool()。close()时,关闭该池。
参考: 使用来自我们的JCG合作伙伴 Marco Castigliego的Apache KeyedObjectPool的ssh连接池,位于“ 删除重复和修复不良名称”博客中。
翻译自: https://www.javacodegeeks.com/2013/02/pool-of-ssh-connections-using-apache-keyedobjectpool.html