栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java > SpringBoot

Spring Boot:Spring Boot整合FTPClient线程池

SpringBoot 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring Boot:Spring Boot整合FTPClient线程池

最近在写一个FTP上传工具,用到了Apache的FTPClient,但是每个线程频繁的创建和销毁FTPClient对象对服务器的压力很大,因此,此处最好使用一个FTPClient连接池。仔细翻了一下Apache的api,发现它并没有一个FTPClientPool的实现,所以,不得不自己写一个FTPClientPool。下面就大体介绍一下开发连接池的整个过程,供大家参考。
我们可以利用Apache提供的common-pool包来协助我们开发连接池。而开发一个简单的对象池,仅需要实现common-pool 包中的ObjectPool和PoolableObjectFactory两个接口即可。

线程池的意义

为了减少频繁创建、销毁对象带来的性能消耗,我们可以利用对象池的技术来实现对象的复用。对象池提供了一种机制,它可以管理对象池中对象的生命周期,提供了获取和释放对象的方法,可以让客户端很方便的使用对象池中的对象。

pom引入依赖
 
        
            commons-net
            commons-net
            3.5
        

        
        
            commons-pool
            commons-pool
            1.6
        

        
            org.apache.commons
            commons-pool2
            2.0
        
创建ftp配置信息

在resources目录下创建ftp.properties配置文件,目录结构如下:

image.png

添加如下的配置信息:

########### FTP用户名称 ###########ftp.userName=hrabbit########### FTP用户密码 ###########ftp.passWord=123456########### FTP主机IP ###########ftp.host=127.0.0.1########### FTP主机端口号 ###########ftp.port=21########### 保存根路径 ###########ftp.baseUrl=/
创建FTPProperties.java配置文件

加载配置内容到Spring中,配置信息基本延用我的就可以。

@Data@Component@PropertySource("classpath:ftp.properties")@ConfigurationProperties(prefix = "ftp")public class FTPProperties {    private String username;    private String password;    private String host;    private Integer port;    private String baseUrl;    private Integer passiveMode = FTP.BINARY_FILE_TYPE;    private String encoding="UTF-8";    private int clientTimeout=120000;    private int bufferSize;    private int transferFileType=FTP.BINARY_FILE_TYPE;    private boolean renameUploaded;    private int retryTime;
}
创建FTPClientPool线程池
@Slf4j@SuppressWarnings("all")public class FTPClientPool implements ObjectPool {    private static final int DEFAULT_POOL_SIZE = 10;    public BlockingQueue blockingQueue;    private FTPClientFactory factory;    public FTPClientPool(FTPClientFactory factory) throws Exception {        this(DEFAULT_POOL_SIZE, factory);
    }    public FTPClientPool(int poolSize, FTPClientFactory factory) throws Exception {        this.factory = factory;        this.blockingQueue = new ArrayBlockingQueue(poolSize);
        initPool(poolSize);
    }    
    private void initPool(int maxPoolSize) throws Exception {        int count = 0;        while(count < maxPoolSize) {            this.addObject();
            count++;
        }
    }    
    @Override
    public FTPClient borrowObject() throws Exception {
        FTPClient client = blockingQueue.take();        if(client == null) {
            client = factory.makeObject();
        } else if(!factory.validateObject(client)) {
            invalidateObject(client);
            client = factory.makeObject();
        }        return client;
    }    
    @Override
    public void returnObject(FTPClient client) throws Exception {        if ((client != null) && !blockingQueue.offer(client,2,TimeUnit.MINUTES)) {            try {
                factory.destroyObject(client);
            } catch (Exception e) {                throw e;
            }
        }
    }    
    @Override
    public void invalidateObject(FTPClient client) throws Exception {
        blockingQueue.remove(client);
    }    
    @Override
    public void addObject() throws Exception {
        blockingQueue.offer(factory.makeObject(), 2, TimeUnit.MINUTES);
    }    
    public FTPClient reconnect() throws Exception {        return factory.makeObject();
    }    
    @Override
    public int getNumIdle() {        return blockingQueue.size();
    }    
    @Override
    public int getNumActive() {        return DEFAULT_POOL_SIZE - getNumIdle();
    }    @Override
    public void clear() throws Exception {

    }    
    @Override
    public void close() {        try {            while(blockingQueue.iterator().hasNext()) {
                FTPClient client = blockingQueue.take();
                factory.destroyObject(client);
            }
        } catch(Exception e) {
            log.error("close ftp client pool failed...{}", e);
        }
    }    
    public void addObject(FTPClient ftpClient) throws Exception {
        blockingQueue.put(ftpClient);
    }
}
创建一个FTPClientFactory工厂类

创建FTPClientFactory实现PoolableObjectFactory的接口,FTPClient工厂类,通过FTPClient工厂提供FTPClient实例的创建和销毁

@Slf4j@SuppressWarnings("all")public class FTPClientFactory implements PoolableObjectFactory {    private FTPProperties ftpProperties;    public FTPClientFactory(FTPProperties ftpProperties) {        this.ftpProperties = ftpProperties;
    }    @Override
    public FTPClient makeObject() throws Exception {
        FTPClient ftpClient = new FTPClient();
        ftpClient.setControlEncoding(ftpProperties.getEncoding());
        ftpClient.setConnectTimeout(ftpProperties.getClientTimeout());        try {
            ftpClient.connect(ftpProperties.getHost(), ftpProperties.getPort());            int reply = ftpClient.getReplyCode();            if (!FTPReply.isPositiveCompletion(reply)) {
                ftpClient.disconnect();
                log.warn("FTPServer refused connection");                return null;
            }            boolean result = ftpClient.login(ftpProperties.getUsername(), ftpProperties.getPassword());
            ftpClient.setFileType(ftpProperties.getTransferFileType());            if (!result) {
                log.warn("ftpClient login failed... username is {}", ftpProperties.getUsername());
            }
        } catch (Exception e) {
            log.error("create ftp connection failed...{}", e);            throw e;
        }        return ftpClient;
    }    @Override
    public void destroyObject(FTPClient ftpClient) throws Exception {        try {            if(ftpClient != null && ftpClient.isConnected()) {
                ftpClient.logout();
            }
        } catch (Exception e) {
            log.error("ftp client logout failed...{}", e);            throw e;
        } finally {            if(ftpClient != null) {
                ftpClient.disconnect();
            }
        }

    }    @Override
    public boolean validateObject(FTPClient ftpClient) {        try {            return ftpClient.sendNoOp();
        } catch (Exception e) {
            log.error("Failed to validate client: {}");
        }        return false;
    }    @Override
    public void activateObject(FTPClient obj) throws Exception {        //Do nothing

    }    @Override
    public void passivateObject(FTPClient obj) throws Exception {        //Do nothing

    }
}
创建FTPUtils.java的工具类

FTPUtils.java中封装了上传、下载等方法,在项目启动的时候,在@PostConstruct注解的作用下通过执行init()的方法,创建FTPClientFactory工厂中,并初始化了FTPClientPool线程池,这样每次调用方法的时候,都直接从FTPClientPool中取出一个FTPClient对象

@Slf4j@Componentpublic class FTPUtils {    
    @Autowired
    public static FTPClientPool ftpClientPool;    
    public static FTPClient ftpClient;    private static FTPUtils ftpUtils;    @Autowired
    private FTPProperties ftpProperties;    
    @PostConstruct
    public boolean init() {
        FTPClientFactory factory = new FTPClientFactory(ftpProperties);
        ftpUtils = this;        try {
            ftpClientPool = new FTPClientPool(factory);
        } catch (Exception e) {
            e.printStackTrace();            return false;
        }        return true;
    }    
    public static FTPClient getFTPClient() throws Exception {        //初始化的时候从队列中取出一个连接
        if (ftpClient==null) {            synchronized (ftpClientPool) {
                ftpClient = ftpClientPool.borrowObject();
            }
        }        return ftpClient;
    }    
    public void complete() throws IOException {
        ftpClient.completePendingCommand();
    }    
    public void disconnect() throws Exception {
        ftpClientPool.addObject(ftpClient);
    }    
    public static boolean uploadFile(String remoteFile, InputStream input)  {        boolean result = false;        try {
            getFTPClient();
            ftpClient.enterLocalPassiveMode();
            result = ftpClient.storeFile(remoteFile, input);
            input.close();
            ftpClient.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        }        return result;
    }    
    public static boolean uploadFile(String remoteFile, String localFile){
        FileInputStream input = null;        try {
            input = new FileInputStream(new File(localFile));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }        return uploadFile(remoteFile, input);
    }    
    public boolean copyFile(String fromFile, String toFile) throws Exception {
        InputStream in=getFileInputStream(fromFile);
        getFTPClient();        boolean flag = ftpClient.storeFile(toFile, in);
        in.close();        return flag;
    }    
    public static InputStream getFileInputStream(String fileName) throws Exception {
        ByteArrayOutputStream fos=new ByteArrayOutputStream();
        getFTPClient();
        ftpClient.retrieveFile(fileName, fos);
        ByteArrayInputStream in=new ByteArrayInputStream(fos.toByteArray());
        fos.close();        return in;
    }    
    public static boolean downFile(String remoteFile, String localFile){        boolean result = false;        try {
            getFTPClient();
            OutputStream os = new FileOutputStream(localFile);
            ftpClient.retrieveFile(remoteFile, os);
            ftpClient.logout();
            ftpClient.disconnect();
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {            try {
            } catch (Exception e) {
                e.printStackTrace();
            }
        }        return result;
    }    
    public static InputStream getInputStream(String filePath) throws Exception {
        getFTPClient();
        InputStream inputStream = ftpClient.retrieveFileStream(filePath);        return inputStream;
    }    
    public boolean rename(String fromFile,String toFile) throws Exception {
        getFTPClient();        boolean result = ftpClient.rename(fromFile,toFile);        return result;
    }    
    public FTPFile[] getFiles(String dir) throws Exception {
        getFTPClient();
        FTPFile[] files = new FTPFile[0];        try {
            files = ftpClient.listFiles(dir);
        }catch (Throwable thr){
            thr.printStackTrace();
        }        return files;
    }    
    public FTPFile[] getFiles(String dir, FTPFileFilter filter) throws Exception {
        getFTPClient();
        FTPFile[] files = new FTPFile[0];        try {
            files = ftpClient.listFiles(dir, filter);
        }catch (Throwable thr){
            thr.printStackTrace();
        }        return files;
    }    
    public boolean makeDirectory(String remoteDir) throws Exception {
        getFTPClient();        boolean result = false;        try {
            result = ftpClient.makeDirectory(remoteDir);
        } catch (IOException e) {
            e.printStackTrace();
        }        return result;
    }    public boolean mkdirs(String dir) throws Exception {        boolean result = false;        if (null == dir) {            return result;
        }
        getFTPClient();
        ftpClient.changeWorkingDirectory("/");
        StringTokenizer dirs = new StringTokenizer(dir, "/");
        String temp = null;        while (dirs.hasMoreElements()) {
            temp = dirs.nextElement().toString();            //创建目录
            ftpClient.makeDirectory(temp);            //进入目录
            ftpClient.changeWorkingDirectory(temp);
            result = true;
        }
        ftpClient.changeWorkingDirectory("/");        return result;
    }
}
创建FtpClientTest.java测试类

上传一张图片到FTP服务器,并将文件重新命名为hrabbit.jpg,代码如下:

@RunWith(SpringRunner.class)@SpringBootTestpublic class FtpClientTest {    
    @Test
    public void uploadFile(){        boolean flag = FTPUtils.uploadFile("hrabbit.jpg", "/Users/mrotaku/Downloads/klklklkl_4x.jpg");
        Assert.assertEquals(true, flag);
    }

}

程序完美运行,这时候我们查看我们的FTP服务器,http://localhost:8866/hrabbit.jpg

image.png



作者:hrabbits
链接:https://www.jianshu.com/p/6270b2308c4e


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/234579.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号