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

Spring Boot整合FTPClient线程池的实现示例

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

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配置文件,目录结构如下:

添加如下的配置信息:

########### 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
@Component
public 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)
@SpringBootTest
public 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

码云地址:https://gitee.com/hrabbit/hrabbit-admin

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持考高分网。

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

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

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