Making: github.com/jayknoxqu/f…
Overview of connection pools
Frequent and close connections, can greatly reduce the performance of the system, and the connection pool will be at the time of initialization will create a certain number of connections, every visit to just get connection from the connection pool and put it back again after using connection pool, and is not directly close the connection, so that the program to reuse the same connection without the need to build and close connection with each visit, This improves system performance.
Commons-pool2 introduction
2.1 Introduction of POOL2
<! Commons-pool2 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.5.0</version>
</dependency>
<! -- Introduce FTPClient as pooled object -->
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.6</version>
</dependency>
Copy the code
2.2 Composition of POOL2
PooledObject PooledObjectFactory ObjectPool
Corresponding to:
FTPClient(pooled object) FTPClientFactory(object factory) FTPClientPool
Diagram:
Three. Connection pooling
3.1 configuration FtpClient
We already have the pooled object (FtpClient), we just need to add the configuration
@ConfigurationProperties(ignoreUnknownFields = false, prefix = "ftp.client")
public class FtpClientProperties {
/ / FTP address
private String host;
/ / the port number
private Integer port = 21;
// Login user
private String username;
// Login password
private String password;
// Passive mode
private boolean passiveMode = false;
/ / code
private String encoding = "UTF-8";
// Connection timeout time (seconds)
private Integer connectTimeout;
// Buffer size
private Integer bufferSize = 1024;
// Transfer file type
private Integer transferFileType;
}
Copy the code
Application.properties is configured to:
Host =127.0.0.1 ftp.client.port=22 ftp.client.username=root ftp.client.password=root ftp.client.encoding= UTF-8 ftp.client.passiveMode=false
ftp.client.connectTimeout=30000
Copy the code
3.2 create FtpClientFactory
There are two kinds of factories in Commons-pool2: PooledObjectFactory and KeyedPooledObjectFactory, which we use.
public interface PooledObjectFactory<T> {
// Create an object
PooledObject<T> makeObject(a);
// Activate the object
void activateObject(PooledObject<T> obj);
// Passivate the object
void passivateObject(PooledObject<T> obj);
// Validate objects
boolean validateObject(PooledObject<T> obj);
// Destroy the object
void destroyObject(PooledObject<T> obj);
}
Copy the code
To create FtpClientFactory, you simply inherit the BasePooledObjectFactory abstract class, which implements PooledObjectFactory
public class FtpClientFactory extends BasePooledObjectFactory<FTPClient> {
private FtpClientProperties config;
public FtpClientFactory(FtpClientProperties config) {
this.config = config;
}
/** * Create an FtpClient object */
@Override
public FTPClient create(a) {
FTPClient ftpClient = new FTPClient();
ftpClient.setControlEncoding(config.getEncoding());
ftpClient.setConnectTimeout(config.getConnectTimeout());
try {
ftpClient.connect(config.getHost(), config.getPort());
int replyCode = ftpClient.getReplyCode();
if(! FTPReply.isPositiveCompletion(replyCode)) { ftpClient.disconnect(); log.warn("FTPServer refused connection,replyCode:{}", replyCode);
return null;
}
if(! ftpClient.login(config.getUsername(), config.getPassword())) { log.warn("ftpClient login failed... username is {}; password: {}", config.getUsername(), config.getPassword());
}
ftpClient.setBufferSize(config.getBufferSize());
ftpClient.setFileType(config.getTransferFileType());
if(config.isPassiveMode()) { ftpClient.enterLocalPassiveMode(); }}catch (IOException e) {
log.error("create ftp connection failed...", e);
}
return ftpClient;
}
/** * encapsulates the object into the pool with PooledObject */
@Override
public PooledObject<FTPClient> wrap(FTPClient ftpClient) {
return new DefaultPooledObject<>(ftpClient);
}
/** * Destroys the FtpClient object */
@Override
public void destroyObject(PooledObject<FTPClient> ftpPooled) {
if (ftpPooled == null) {
return;
}
FTPClient ftpClient = ftpPooled.getObject();
try {
if(ftpClient.isConnected()) { ftpClient.logout(); }}catch (IOException io) {
log.error("ftp client logout failed... {}", io);
} finally {
try {
ftpClient.disconnect();
} catch (IOException io) {
log.error("close ftp client failed... {}", io); }}}/** * Verify the FtpClient object */
@Override
public boolean validateObject(PooledObject<FTPClient> ftpPooled) {
try {
FTPClient ftpClient = ftpPooled.getObject();
return ftpClient.sendNoOp();
} catch (IOException e) {
log.error("Failed to validate client: {}", e);
}
return false; }}Copy the code
3.3 implementation FtpClientPool
In Commons-pool2, three object pools are preset that can be used directly: GenericObjectPool, GenericKeyedObjectPool, and SoftReferenceObjectPool
In the columns:
GenericObjectPool<FTPClient> ftpClientPool = new GenericObjectPool<>(new FtpClientFactory());
Copy the code
We can also implement a connection pool ourselves:
public interface ObjectPool<T> extends Closeable {
// Get an object from the pool
T borrowObject(a);
Return an object to the pool
void returnObject(T obj);
// Discard an invalid object
void invalidateObject(T obj);
// Add objects to the pool
void addObject(a);
// Clear the object pool
void clear(a);
// Close the object pool
void close(a);
}
Copy the code
ObjectPool is implemented by inheriting BaseObjectPool
public class FtpClientPool extends BaseObjectPool<FTPClient> {
private static final int DEFAULT_POOL_SIZE = 8;
private final BlockingQueue<FTPClient> ftpBlockingQueue;
private final FtpClientFactory ftpClientFactory;
/** * To initialize the connection pool, inject a factory to provide the FTPClient instance **@paramFtpClientFactory FTP factory *@throws Exception
*/
public FtpClientPool(FtpClientFactory ftpClientFactory) throws Exception {
this(DEFAULT_POOL_SIZE, ftpClientFactory);
}
public FtpClientPool(int poolSize, FtpClientFactory factory) throws Exception {
this.ftpClientFactory = factory;
ftpBlockingQueue = new ArrayBlockingQueue<>(poolSize);
initPool(poolSize);
}
/** * To initialize the connection pool, inject a factory to provide the FTPClient instance **@paramMaxPoolSize Maximum number of connections *@throws Exception
*/
private void initPool(int maxPoolSize) throws Exception {
for (int i = 0; i < maxPoolSize; i++) {
// Add objects to the pooladdObject(); }}/** * get the object */ from the connection pool
@Override
public FTPClient borrowObject(a) throws Exception {
FTPClient client = ftpBlockingQueue.take();
if (ObjectUtils.isEmpty(client)) {
client = ftpClientFactory.create();
// Add the connection pool
returnObject(client);
// Verify that the object is valid
} else if(! ftpClientFactory.validateObject(ftpClientFactory.wrap(client))) {// Process invalid objects
invalidateObject(client);
// Create a new object
client = ftpClientFactory.create();
// Add the new object to the connection pool
returnObject(client);
}
return client;
}
/** * return the object to the connection pool */
@Override
public void returnObject(FTPClient client) {
try {
if(client ! =null && !ftpBlockingQueue.offer(client, 3, TimeUnit.SECONDS)) { ftpClientFactory.destroyObject(ftpClientFactory.wrap(client)); }}catch (InterruptedException e) {
log.error("return ftp client interrupted ... {}", e); }}/** * remove invalid object */
@Override
public void invalidateObject(FTPClient client) {
try {
client.changeWorkingDirectory("/");
} catch (IOException e) {
e.printStackTrace();
} finally{ ftpBlockingQueue.remove(client); }}/** * add a new link */
@Override
public void addObject(a) throws Exception {
// Insert objects into the queue
ftpBlockingQueue.offer(ftpClientFactory.create(), 3, TimeUnit.SECONDS);
}
/** * close connection pool */
@Override
public void close(a) {
try {
while(ftpBlockingQueue.iterator().hasNext()) { FTPClient client = ftpBlockingQueue.take(); ftpClientFactory.destroyObject(ftpClientFactory.wrap(client)); }}catch (Exception e) {
log.error("close ftp client ftpBlockingQueue failed... {}", e); }}}Copy the code
It is not advisable to implement connection pooling yourself, which incurs additional maintenance costs…
Iv. Code Address:
Making: github.com/jayknoxqu/f…
V. References:
FTPClient connection pool implementation: yq.aliyun.com/articles/59…
Apache Commons – pool2 (finishing) : www.jianshu.com/p/b0189e01d…
The officer scheme column: commons.apache.org/proper/comm…