1、FtpManager 类中,需要创建连接池管理的Map
private static ConcurrentHashMap<String, FtpClientPool> pools = new ConcurrentHashMap<String, FtpClientPool>();
2、定义具体的操作方法,如删除
public static void deleteFiles(List<FtpEntity> ftpEntitys, String filePath, Set<String> fileNames) throws Exception {
if (null == fileNames || fileNames.size() <= 0) {
return;
}
Exception e = null;
for (FtpEntity ftpEntity : ftpEntitys) {
FTPClient ftpClient = null;
try {
ftpClient = borrowClient(ftpEntity);
makeDirectory(ftpClient, ftpEntity.getTemp(), filePath);
for (String fileName : fileNames) {
try {
ftpClient.deleteFile(fileName);
} catch (Exception e1) {
LOGGER.log(Level.SEVERE, "delete " + fileName + " error", e1);
}
}
} catch (Exception ex) {
LOGGER.log(Level.SEVERE, "uploadFile error", ex);
returnBrokenClient(ftpClient);
ftpClient = null;
e = ex;
} finally {
if (ftpClient != null) {
returnClient(ftpClient);
}
}
}
if (null != e) {
throw e;
}
}
3、borrowClient 是哪里来的呢??
public static FTPClient borrowClient(FtpEntity ftpEntity) {
String url = ftpEntity.getUrl();
if (!url.endsWith(SPLITTER)) {
url = url + SPLITTER;
}
String hostName = url.substring(FTP_FIX, url.indexOf(SPLITTER, FTP_FIX));
String username = ftpEntity.getUsername();
String password = ftpEntity.getPassword();
String poolId = constructPoolId(hostName, username, password);
FtpClientPool pool = pools.get(poolId);
if (pool == null) {
final FtpClientPool value = new FtpClientPool(hostName, username, password);
pool = pools.putIfAbsent(poolId, value);
if (pool == null) {
pool = value;
}
}
return pool.borrowClient();
}
4、FtpClientPool 哪里来的呢? 它是ftpManager 的一个内部类
private static class FtpClientPool {
private final GenericObjectPool<FTPClient> internalPool;
private FtpClientPool(String hostname, String username, String password) {
this.internalPool = new GenericObjectPool<FTPClient>(new FtpClientFactory(hostname, username, password));
// this is important,change to root dir when borrow from pool,ref validateObject method.
this.internalPool.setTestOnBorrow(true);
this.internalPool.setMaxTotal(50);
this.internalPool.setMaxIdle(16);
// this.internalPool.setMinEvictableIdleTimeMillis(60000);
// this.internalPool.setTimeBetweenEvictionRunsMillis(60000);
// this.internalPool.setTestWhileIdle(true);
this.internalPool.setBlockWhenExhausted(true);
// this.internalPool.setNumTestsPerEvictionRun(10);
// this.internalPool.setMaxTotal(Integer.MAX_VALUE);
this.internalPool.setMaxWaitMillis(MaxWaitMillis);
// this.internalPool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_GROW);
}
/**
* 功能描述: <br>
* 获取链接 〈功能详细描述〉
*
* @return
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
public FTPClient borrowClient() {
try {
return this.internalPool.borrowObject();
} catch (Exception e) {
throw new RuntimeException("Could not borrowClient from pool", e);
}
}
/**
* 功能描述: <br>
* 初始化连接 〈功能详细描述〉
*
* @param client
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
public void returnClient(FTPClient client) {
try {
this.internalPool.returnObject(client);
} catch (Exception e) {
// LOGGER.log(Level.WARNING, "Could not returnClient from pool", e);
}
}
public void returnBrokenClient(FTPClient client) {
try {
this.internalPool.invalidateObject(client);
} catch (Exception e) {
// LOGGER.log(Level.WARNING, "Could not returnBrokenClient from pool", e);
}
}
/**
* 功能描述: <br>
* 销毁链接 〈功能详细描述〉
*
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
public void destroy() {
try {
this.internalPool.close();
} catch (Exception e) {
// LOGGER.log(Level.WARNING, "Could not destroy pool", e);
}
}
}
5、FtpClientFactory 哪里来的呢?它也是一个内部类
private static class FtpClientFactory implements PooledObjectFactory<FTPClient> {
private String hostname;
private String username;
private String password;
private FtpClientFactory(String hostname, String username, String password) {
this.hostname = hostname;
this.username = username;
this.password = password;
}
/*
* (non-Javadoc)
* @see org.apache.commons.pool.BasePoolableObjectFactory#makeObject()
*/
public FtpClientWrapper create() throws Exception {
FtpClientWrapper ftpClient = null;
Boolean flag = false;
Exception e = null;
for (int i = 0; i < RECONNECT_TIMES; i++) {
try {
ftpClient = new FtpClientWrapper(this.hostname, this.username, this.password);
ftpClient.setConnectTimeout(CONNECT_TIMEOUT);
// ftpClient.setDefaultTimeout(CONNECT_TIMEOUT);
ftpClient.setControlEncoding("utf-8");
ftpClient.connect(hostname);
ftpClient.setDataTimeout(DATA_TIMEOUT);
int reply = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftpClient.disconnect();
throw new Exception("FTP Connect fail");
}
if (!ftpClient.login(username, password)) {
ftpClient.disconnect();
throw new Exception("Invalid username and password");
}
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
ftpClient.setBufferSize(BUFFER_SIZE);
ftpClient.enterLocalPassiveMode();
ftpClient.setRootDir(ftpClient.printWorkingDirectory());
flag = true;
break;
} catch (Exception ex) {
// LOGGER.log(Level.WARNING, "test....Can not create ftpClient," + this.hostname, ex);
try {
destroyObject(ftpClient);
} catch (Exception e1) {
// LOGGER.log(Level.WARNING, "test...Can not close ftpClient," + this.hostname, e1);
}
e = ex;
Thread.sleep(RECONNECT_SLEEP_TIME);
}
}
if (!flag) {
// LOGGER.log(Level.WARNING, "test....Can not create ftpClient in three times," + this.hostname);
try {
destroyObject(ftpClient);
} catch (Exception e1) {
// LOGGER.log(Level.WARNING, "Can not close ftpClient", e1);
}
throw new Exception(hostname + " cat not connect.", e);
}
return ftpClient;
}
public void destroyObject(FTPClient ftpClient) throws Exception {
closeFtpClient(ftpClient);
}
@Override
public PooledObject<FTPClient> makeObject() throws Exception {
// TODO Auto-generated method stub
return new DefaultPooledObject<FTPClient>(create());
}
@Override
public void destroyObject(PooledObject<FTPClient> p) throws Exception {
closeFtpClient(p.getObject());
}
@Override
public boolean validateObject(PooledObject<FTPClient> p) {
try {
((FtpClientWrapper) p.getObject()).changeToRootDir();
return true;
} catch (Exception e) {
// LOGGER.log(Level.WARNING, "failed to changeToRootDir,validate failed.");
throw new RuntimeException("Failed to validate client: " + e, e);
}
}
@Override
public void activateObject(PooledObject<FTPClient> p) throws Exception {
// TODO Auto-generated method stub
}
@Override
public void passivateObject(PooledObject<FTPClient> p) throws Exception {
// TODO Auto-generated method stub
}
}
6、FtpClientWrapper 哪里来的呢,没错,还是内部类
public static class FtpClientWrapper extends FTPClient {
private String poolId;
private String rootDir;
public FtpClientWrapper(String ip, String username, String password) {
super();
this.poolId = constructPoolId(ip, username, password);
}
/**
* 功能描述: <br>
* get set方法 〈功能详细描述〉
*
* @return : id
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
public String getPoolId() {
return poolId;
}
/**
* 功能描述: <br>
* get set方法 〈功能详细描述〉
*
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
public void setRootDir(String rootDir) {
this.rootDir = rootDir;
}
/**
* 功能描述: <br>
* 返回根目录 〈功能详细描述〉
*
* @throws Exception
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
public void changeToRootDir() throws Exception {
changeWorkingDirectory(rootDir);
}
}