自定义 ftpClient / ftp client 连接池

项目中要用到ftp上传文件, 但可能会出现很多人批量上传, 所以就想着弄一个client的池子,在网上搜索了一番,自己改进了一番
总共需要三个类:

  • 一个配置类 FTPClientConfigure. 是ftp的连接信息
  • 一个工厂类 FtpClientFactory 通过配置信息创建client对象,以及销毁,验证对象
  • 一个poo类 FtpClientPool 工厂创建的client对象都存在pool里

具体如下

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);

最后注意,我是写好代码后发到的这里,还没在项目中使用, 可能存在bug,但也可能没有bug

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值