项目中要用到ftp上传文件, 但可能会出现很多人批量上传, 所以就想着弄一个client的池子,在网上搜索了一番,自己改进了一番
总共需要三个类:
具体如下
1.创建配置类
public class FTPClientConfigure {
private String host;
private int port;
private String username;
private String password;
private String passiveMode;
private String encoding;
private int clientTimeout;
private int threadNum;
private int transferFileType;
private boolean renameUploaded;
private int retryTimes;
private String path;
// get set 方法省略
2.创建工厂类
package ....;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
/**
* author:
* create: 2019-04-29 11:19
* description:
**/
public class FtpClientFactory extends BasePooledObjectFactory<FTPClient> {
private static Logger logger = LoggerFactory.getLogger(FtpClientFactory.class);
private FTPClientConfigure config;
public FtpClientFactory(FTPClientConfigure config) {
this.config = config;
}
/**
* 创建FtpClient对象
*/
@Override
public FTPClient create() {
FTPClient ftpClient = new FTPClient();
ftpClient.setControlEncoding(config.getEncoding());
ftpClient.setConnectTimeout(config.getClientTimeout());
try {
ftpClient.connect(config.getHost(), config.getPort());
int replyCode = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(replyCode)) {
ftpClient.disconnect();
logger.warn("服务器拒绝连接,检查ip和端口是否正确");
return null;
}
boolean login = ftpClient.login(config.getUsername(), config.getPassword());
if (!login) {
throw new RuntimeException("登陆ftp文件系统失败! userName:" + config.getUsername() + " ; password:" + config.getPassword());
}
ftpClient.setFileType(config.getTransferFileType());
} catch (IOException e) {
logger.error("创建ftp连接失败...", e);
}
return ftpClient;
}
/**
* 用PooledObject封装对象放入池中
*/
@Override
public PooledObject<FTPClient> wrap(FTPClient ftpClient) {
return new DefaultPooledObject<>(ftpClient);
}
/**
* 销毁FtpClient对象
*/
@Override
public void destroyObject(PooledObject<FTPClient> ftpPooled) {
if (ftpPooled == null) {
return;
}
FTPClient ftpClient = ftpPooled.getObject();
destroyObject(ftpClient);
}
public void destroyObject(FTPClient ftpClient) {
if (ftpClient == null) {
return;
}
try {
if (ftpClient.isConnected()) {
ftpClient.logout();
}
} catch (IOException io) {
logger.error("ftp client 退出失败", io);
} finally {
try {
ftpClient.disconnect();
} catch (IOException io) {
logger.error("ftp client 关闭失败", io);
}
}
}
/**
* 验证FtpClient对象
*/
@Override
public boolean validateObject(PooledObject<FTPClient> ftpPooled) {
FTPClient ftpClient = ftpPooled.getObject();
return validateObject(ftpClient);
}
public boolean validateObject(FTPClient ftpClient) {
try {
return ftpClient.sendNoOp();
} catch (IOException e) {
logger.error("验证fpt client 失败", e);
}
return false;
}
}
3.创建池子pool
package ...r;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.pool2.BaseObjectPool;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
/**
* author:
* create: 2019-04-29 10:05
* description: ...
**/
public class FtpClientPool extends BaseObjectPool<FTPClient> {
private static final FtpClientPool ftpClientPool = new FtpClientPool(new FtpClientFactory(new FTPClientConfigure()));
private static final int IDLE_POOL_SIZE = 5;
private static final int MAX_CLIENT_SIZE = 20;
private int allClient = 0;
private final BlockingQueue<FTPClient> pool;
private final FtpClientFactory factory;
public static FtpClientPool getInstance(){
return ftpClientPool;
}
/**
* 初始化连接池,需要注入一个工厂来提供FTPClient实例
* @param idleSize
*/
private FtpClientPool(FtpClientFactory factory){
this(IDLE_POOL_SIZE, factory);
}
/**
* 初始化连接池,需要注入一个工厂来提供FTPClient,和初始化连接池的大小
*
* @param idleSize
* @param factory
*/
private FtpClientPool(int idleSize, FtpClientFactory factory) {
this.factory = factory;
pool = new ArrayBlockingQueue<>(idleSize);
initPool(idleSize);
}
private void initPool(int idleSize) {
for (int i = 0; i < idleSize; i++) {
//插入对象到队列,offer为非阻塞,如果等待3秒还是满的,则放弃加入
try {
pool.offer(factory.create(), 3, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
allClient++;
}
}
/**
*
* 借出对象,就是获取client
*/
@Override
public FTPClient borrowObject() {
// 非阻塞获取(具体可查询BlockingQueue的使用方式)
FTPClient client = pool.poll();
// 如果pool中没有client
if (client == null) {
//已存在的client没有超过最大数量,创建.
if (allClient < MAX_CLIENT_SIZE) {
client = factory.create();
allClient++;
} else {
// 已存在的client超过了最大数量,当前线程阻塞获取,一直等到拿到client.
try {
client = pool.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} else if (!factory.validateObject(client)) {
// 获取到了client,但验证不通过,从池中移除
invalidateObject(client);
//制造新对象
client = factory.create();
}
return client;
}
/**
* 放回到池中
* @param client
*/
@Override
public void returnObject(FTPClient client) {
if (null == client) {
return;
}
// 放入池中
boolean put = false;
try {
put = pool.offer(client, 3, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (!put) {
// 池中已满,断开连接,销毁
try {
factory.destroyObject(client);
} catch (Exception e) {
e.printStackTrace();
}
}
allClient--;
}
/**
* 作废
* @param client
*/
@Override
public void invalidateObject(FTPClient client){
//移除无效的客户端
pool.remove(client);
}
}
这样就可以用了
// 初始化pool
FtpClientPool pool = FtpClientPool.getInstance();
// 获取client
FTPClient ftpClient = pool.borrowObject();
// ......自己的业务逻辑,包括切换目录,上传,下载......
// 返回client
pool.returnObject(ftpClient);