一. 连接池概述

​       频繁的建立和关闭连接,会极大的降低系统的性能,而连接池会在初始化的时候会创建一定数量的连接,每次访问只需从连接池里获取连接,使用完毕后再放回连接池,并不是直接关闭连接,这样可以保证程序重复使用同一个连接而不需要每次访问都建立和关闭连接, 从而提高系统性能。有些对象的创建开销是比较大的,比如数据库连接等。为了减少频繁创建、销毁对象带来的性能消耗,我们可以利用对象池的技术来实现对象的复用。对象池提供了一种机制,它可以管理对象池中对象的生命周期,提供了获取和释放对象的方法,可以让客户端很方便的使用对象池中的对象。

二. commons-pool2介绍

2.1 pool2的引入

<dependency><groupId>commons-lang</groupId><artifactId>commons-lang</artifactId><version>2.5</version>
</dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.8.0</version>
</dependency>
<dependency><groupId>commons-net</groupId><artifactId>commons-net</artifactId><version>3.6</version>
</dependency>
<dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version>
</dependency>

2.2 pool2的组成

PooledObject(池化对象) PooledObjectFactory(对象工厂) ObjectPool (对象池)

对应为: FTPClient(池化对象) FTPClientFactory(对象工厂) FTPClientPool(对象池)

关系图:

关系图

三. 实现连接池

3.1 配置FtpClient

我们已经有现成的池化对象(FtpClient)了,只需要添加配置即可,FTPClientConfig【FTP连接配置类】


/** * Licensed to the Apache Software Foundation (ASF) under one or more* contributor license agreements.  See the NOTICE file distributed with* this work for additional information regarding copyright ownership.* The ASF licenses this file to You under the Apache License, Version 2.0* (the "License"); you may not use this file except in compliance with* the License.  You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.**/
package com.tompai.ftp.pool;import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;/*** @desc: demo* @name: FTPClientConfig.java* @author: tompai* @email:liinux@qq.com* @createTime: 2019年12月31日 下午12:53:48* @history:* @version: v1.0*/public class FTPClientConfig extends GenericObjectPoolConfig<FTPClient> {private String host;// 主机名private int port = 21;// 端口private String username;// 用户名private String password;// 密码private int connectTimeOut = 5000;// ftp 连接超时时间 毫秒private String controlEncoding = "utf-8";private int bufferSize = 1024;// 缓冲区大小private int fileType = 2;// 传输数据格式 2表binary二进制数据private int dataTimeout = 120 * 1000;private boolean useEPSVwithIPv4 = false;private boolean passiveMode = true;// 是否启用被动模式private int threadNum=1;//开启线程数private int transferFileType=FTPClient.BINARY_FILE_TYPE;//传输文件类型private boolean renameUploaded=false;//是否上传文件重命名;private int retryTimes=3;//重试次数public String getHost() {return host;}public void setHost(String host) {this.host = host;}public int getPort() {return port;}public void setPort(int port) {this.port = port;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public int getConnectTimeOut() {return connectTimeOut;}public void setConnectTimeOut(int connectTimeOut) {this.connectTimeOut = connectTimeOut;}public String getControlEncoding() {return controlEncoding;}public void setControlEncoding(String controlEncoding) {this.controlEncoding = controlEncoding;}public int getBufferSize() {return bufferSize;}public void setBufferSize(int bufferSize) {this.bufferSize = bufferSize;}public int getFileType() {return fileType;}public void setFileType(int fileType) {this.fileType = fileType;}public int getDataTimeout() {return dataTimeout;}public void setDataTimeout(int dataTimeout) {this.dataTimeout = dataTimeout;}public boolean isUseEPSVwithIPv4() {return useEPSVwithIPv4;}public void setUseEPSVwithIPv4(boolean useEPSVwithIPv4) {this.useEPSVwithIPv4 = useEPSVwithIPv4;}public boolean isPassiveMode() {return passiveMode;}public void setPassiveMode(boolean passiveMode) {this.passiveMode = passiveMode;}public int getThreadNum() {return threadNum;}public void setThreadNum(int threadNum) {this.threadNum = threadNum;}public int getTransferFileType() {return transferFileType;}public void setTransferFileType(int transferFileType) {this.transferFileType = transferFileType;}public boolean isRenameUploaded() {return renameUploaded;}public void setRenameUploaded(boolean renameUploaded) {this.renameUploaded = renameUploaded;}public int getRetryTimes() {return retryTimes;}public void setRetryTimes(int retryTimes) {this.retryTimes = retryTimes;}@Overridepublic String toString() {return "{\"host\":\"" + host + "\", \"port\":\"" + port + "\", \"username\":\"" + username+ "\", \"password\":\"" + password + "\", \"connectTimeOut\":\"" + connectTimeOut+ "\", \"controlEncoding\":\"" + controlEncoding + "\", \"bufferSize\":\"" + bufferSize+ "\", \"fileType\":\"" + fileType + "\", \"dataTimeout\":\"" + dataTimeout+ "\", \"useEPSVwithIPv4\":\"" + useEPSVwithIPv4 + "\", \"passiveMode\":\"" + passiveMode+ "\", \"threadNum\":\"" + threadNum + "\", \"transferFileType\":\"" + transferFileType+ "\", \"renameUploaded\":\"" + renameUploaded + "\", \"retryTimes\":\"" + retryTimes + "\"}";}}

3.2 创建FTPClientFactory

​​ 在commons-pool2中有两种工厂:PooledObjectFactory 和KeyedPooledObjectFactory,在此使用PooledObjectFactory。


/** * Licensed to the Apache Software Foundation (ASF) under one or more* contributor license agreements.  See the NOTICE file distributed with* this work for additional information regarding copyright ownership.* The ASF licenses this file to You under the Apache License, Version 2.0* (the "License"); you may not use this file except in compliance with* the License.  You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.**/
package com.tompai.ftp.pool;import java.io.IOException;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;/*** @desc: demo* @name: FTPClientFactory.java* @author: tompai* @email:liinux@qq.com* @createTime: 2019年12月31日 下午12:52:02* @history:* @version: v1.0*/public class FTPClientFactory extends BasePooledObjectFactory<FTPClient> {private static Logger logger = LoggerFactory.getLogger(FTPClientFactory.class);private FTPClientConfig config;public FTPClientConfig getFtpPoolConfig() {return config;}public void setFtpPoolConfig(FTPClientConfig ftpPoolConfig) {this.config = ftpPoolConfig;}/*** 新建对象*/@Overridepublic FTPClient create() throws Exception {FTPClient ftpClient = new FTPClient();ftpClient.setConnectTimeout(config.getConnectTimeOut());try {logger.info("连接ftp服务器:" + config.getHost() + ":" + config.getPort());ftpClient.connect(config.getHost(), config.getPort());int reply = ftpClient.getReplyCode();if (!FTPReply.isPositiveCompletion(reply)) {ftpClient.disconnect();logger.error("FTPServer 拒绝连接!");return null;}boolean result = ftpClient.login(config.getUsername(), config.getPassword());if (!result) {logger.error("ftpClient登录失败!");throw new Exception("ftpClient登录失败! userName:" + config.getUsername() + ", password:" + config.getPassword());}ftpClient.setControlEncoding(config.getControlEncoding());ftpClient.setBufferSize(config.getBufferSize());ftpClient.setFileType(config.getFileType());ftpClient.setDataTimeout(config.getDataTimeout());ftpClient.setUseEPSVwithIPv4(config.isUseEPSVwithIPv4());if (config.isPassiveMode()) {logger.info("进入ftp被动模式");ftpClient.enterLocalPassiveMode();// 进入被动模式}} catch (IOException e) {logger.error("FTP连接失败:", e);}return ftpClient;}@Overridepublic PooledObject<FTPClient> wrap(FTPClient ftpClient) {return new DefaultPooledObject<FTPClient>(ftpClient);}/*** 销毁对象*/@Overridepublic void destroyObject(PooledObject<FTPClient> p) throws Exception {FTPClient ftpClient = p.getObject();if (ftpClient != null && ftpClient.isConnected()) {ftpClient.logout();ftpClient.disconnect();super.destroyObject(p);}}/*** 验证对象*/@Overridepublic boolean validateObject(PooledObject<FTPClient> p) {FTPClient ftpClient = p.getObject();boolean connect = false;try {connect = ftpClient.sendNoOp();} catch (IOException e) {e.printStackTrace();}return connect;}/*** No-op.** @param p ignored*/@Overridepublic void activateObject(PooledObject<FTPClient> p) throws Exception {// The default implementation is a no-op.}/*** No-op.** @param p ignored*/@Overridepublic void passivateObject(PooledObject<FTPClient> p) throws Exception {// The default implementation is a no-op.}
}

3.3 实现FTPClientPool

​ 在commons-pool2中预设了三个可以直接使用的对象池:GenericObjectPool、GenericKeyedObjectPool和SoftReferenceObjectPool,在此使用GenericObjectPool<FTPClient>


/** * Licensed to the Apache Software Foundation (ASF) under one or more* contributor license agreements.  See the NOTICE file distributed with* this work for additional information regarding copyright ownership.* The ASF licenses this file to You under the Apache License, Version 2.0* (the "License"); you may not use this file except in compliance with* the License.  You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.**/
package com.tompai.ftp.pool;import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** @desc: demo* @name: FTPClientPool.java* @author: tompai* @email:liinux@qq.com* @createTime: 2019年12月31日 下午12:54:10* @history:* @version: v1.0*/public class FTPClientPool {private static Logger logger =LoggerFactory.getLogger(FTPClientPool.class);private GenericObjectPool<FTPClient> pool;private FTPClientFactory factory;public FTPClientPool(FTPClientFactory clientFactory) {this.factory = clientFactory;pool = new GenericObjectPool<FTPClient>(clientFactory, clientFactory.getFtpPoolConfig());}public FTPClientFactory getClientFactory() {return factory;}public GenericObjectPool<FTPClient> getPool() {return pool;}/*** 借 获取一个连接对象* * @return* @throws Exception*/public FTPClient borrowObject() throws Exception {FTPClient client = pool.borrowObject();if (!client.sendNoOp()) {// 使池中的对象无效client.logout();client.disconnect();pool.invalidateObject(client);client = factory.create();pool.addObject();}return client;}/*** 还 归还一个连接对象* * @param ftpClient*/public void returnObject(FTPClient ftpClient) {if (ftpClient != null) {pool.returnObject(ftpClient);}}
}

3.4 连接池使用工具类FTPClientHelper


/** * Licensed to the Apache Software Foundation (ASF) under one or more* contributor license agreements.  See the NOTICE file distributed with* this work for additional information regarding copyright ownership.* The ASF licenses this file to You under the Apache License, Version 2.0* (the "License"); you may not use this file except in compliance with* the License.  You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.**/
package com.tompai.ftp.pool;import java.io.IOException;
import java.io.InputStream;import org.apache.commons.io.IOUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** @desc: demo* @name: FTPClientHelper.java* @author: tompai* @email:liinux@qq.com* @createTime: 2019年12月31日 下午1:14:20* @history:* @version: v1.0*/public class FTPClientHelper implements AutoCloseable {private static Logger logger = LoggerFactory.getLogger(FTPClientHelper.class);private FTPClientPool pool;public void setFtpClientPool(FTPClientPool ftpClientPool) {this.pool = ftpClientPool;}/*** 列出目录下的所有文件* @author: tompai* @createTime: 2019年12月31日 下午1:56:02* @history:* @param pathname* @return* @throws Exception FTPFile[]*/public FTPFile[] listFiles(String pathname) {FTPClient client = getClient();try {return client.listFiles(pathname);} catch (IOException e) {//TODO Auto-generated catch blocklogger.error(e.getMessage());e.printStackTrace();}finally {pool.returnObject(client);}return null;}/*** 下载 remote文件流* @author: tompai* @createTime: 2019年12月31日 下午1:52:07* @history:* @param remote* @return byte[]*/public byte[] retrieveFileStream(String remote) {FTPClient client = getClient();InputStream in = null;//byte[] result=new Byte[]try {in = client.retrieveFileStream(remote);return IOUtils.toByteArray(in);} catch (IOException e) {logger.error(e.getMessage());// TODO Auto-generated catch blocke.printStackTrace();} finally {pool.returnObject(client);}return null;}/*** 上传文件* @author: tompai* @createTime: 2019年12月31日 下午1:53:07* @history:* @param remote* @param local* @return* @throws Exception boolean*/public boolean storeFile(String remote, InputStream local) throws Exception {FTPClient client = getClient();try {return client.storeFile(remote, local);} finally {pool.returnObject(client);}}/*** 创建目录 单个不可递归* @author: tompai* @createTime: 2019年12月31日 下午1:52:24* @history:* @param pathname* @return* @throws Exception boolean*/public boolean makeDirectory(String pathname) throws Exception {FTPClient client = getClient();try {return client.makeDirectory(pathname);} finally {pool.returnObject(client);}}/*** 删除目录,单个不可递归* @author: tompai* @createTime: 2019年12月31日 下午1:52:42* @history:* @param pathname* @return* @throws Exception boolean*/public boolean removeDirectory(String pathname) throws Exception {FTPClient client = getClient();try {return client.removeDirectory(pathname);} finally {pool.returnObject(client);}}/*** 删除文件 单个 ,不可递归* @author: tompai* @createTime: 2019年12月31日 下午1:52:54* @history:* @param pathname* @return* @throws Exception boolean*/public boolean deleteFile(String pathname) throws Exception {FTPClient client = getClient();try {return client.deleteFile(pathname);} finally {pool.returnObject(client);}}/*** 获取一个连接对象* * @author: tompai* @createTime: 2019年12月31日 下午1:45:46* @history:* @return FTPClient*/private FTPClient getClient() {FTPClient client = null;try {client = pool.borrowObject();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}return client;}/*** 释放连接* * @author: tompai* @createTime: 2019年12月31日 下午1:45:03* @history:* @param client void*/private void releaseClient(FTPClient client) {if (client == null) {return;}try {pool.returnObject(client);} catch (Exception e) {logger.error("Could not return the ftpClient to the pool", e);// destoryFtpClientif (client.isAvailable()) {try {client.logout();client.disconnect();pool.getPool().invalidateObject(client);} catch (Exception io) {logger.error(io.getMessage());}}}}@Overridepublic void close() throws Exception {// TODO Auto-generated method stublogger.info("---Resources Closed---.");}
}

3.5 连接池测试类FTPLinkPoolTest

在此可以自己使用FileZilla Server for Windows搭建一个简单的FTP服务器;


/** * Licensed to the Apache Software Foundation (ASF) under one or more* contributor license agreements.  See the NOTICE file distributed with* this work for additional information regarding copyright ownership.* The ASF licenses this file to You under the Apache License, Version 2.0* (the "License"); you may not use this file except in compliance with* the License.  You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.**/
package com.tompai.ftp.pool;import org.apache.commons.net.ftp.FTPFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/**
* @desc: demo
* @name: FTPLinkPoolTest.java
* @author: tompai
* @email:liinux@qq.com
* @createTime: 2019年12月31日 下午1:13:51
* @history:
* @version: v1.0
*/public class FTPLinkPoolTest {private static Logger logger =LoggerFactory.getLogger(FTPClientPool.class);/*** @author: tompai* @createTime: 2019年12月31日 下午1:13:51* @history:* @param args void*/public static void main(String[] args) {//TODO Auto-generated method stubFTPClientConfig conf=new FTPClientConfig();conf.setHost("127.0.0.1");conf.setUsername("test");conf.setPassword("test");FTPClientFactory factory=new FTPClientFactory();factory.setFtpPoolConfig(conf);FTPClientPool pool=new FTPClientPool(factory);FTPClientHelper clientHelper=new FTPClientHelper();clientHelper.setFtpClientPool(pool);String pathname="/0821";FTPFile[] files=clientHelper.listFiles(pathname);for(FTPFile file:files) {String name=file.getName();logger.info("name:{}",name);}}}

3.6 测试结果

使用Apache commons-pool2实现高效的FTPClient连接池的方法相关推荐

  1. java.lang.NoClassDefFoundError: org/apache/commons/pool2/PooledObjectFactory

    用GenericObjectPool来连接postgres数据库,在pom.xml中也加入了依赖 <!-- https://mvnrepository.com/artifact/org.apac ...

  2. java ftpclient 池_Java FTPClient连接池的实现

    最近在写一个FTP上传工具,用到了Apache的FTPClient,为了提高上传效率,我采用了多线程的方式,但是每个线程频繁的创建和销毁FTPClient对象势必会造成不必要的开销,因此,此处最好使用 ...

  3. 面试官问:对象池技术了解吗?apache common pool2呢?

    欢迎关注方志朋的博客,回复"666"获面试宝典 对象池顾名思义就是存放对象的池,与我们常听到的线程池.数据库连接池.http连接池等一样,都是典型的池化设计思想. 对象池的优点就是 ...

  4. common pool2 mysql_连接池Commons Pool2的使用

    客户端这边,如果每次都临时建立一个新的连接,那么连接的开销非常大. 业内常用的连接池组件是 Commons Pool2---版本 2.4.2 packageservice.pool; importor ...

  5. commons.pool2 对象池的使用

    commons.pool2 对象池的使用 ? 1 2 3 4 5 <dependency>     <groupId>org.apache.commons</groupI ...

  6. 编写更少量的代码:使用apache commons工具类库

    Commons-configuration Commons-FileUploadCommons DbUtilsCommons BeanUtils Commons CLI Commons CodecCo ...

  7. [转]Apache Commons IO入门教程

    Apache Commons IO是Apache基金会创建并维护的Java函数库.它提供了许多类使得开发者的常见任务变得简单,同时减少重复(boiler-plate)代码,这些代码可能遍布于每个独立的 ...

  8. Apache Commons IO教程:初学者指南

    Apache Commons IO是由Apache Foundation创建和维护的Java库. 它提供了许多类,使开发人员可以轻松地完成常见任务,并且减少样板代码 ,而每个项目都需要一遍又一遍地编写 ...

  9. Apache java文件比对,Java Apache Commons的字符串比较

    1、使用Apache Commons的equals()实现字符串比较 StringUtils类的equals()方法是String类方法equals()的增强版,它会处理null值:assertTha ...

  10. 一篇关于apache commons类库的详解

    1.1. 开篇 在Java的世界,有很多(成千上万)开源的框架,有成功的,也有不那么成功的,有声名显赫的,也有默默无闻的.在我看来,成功而默默无闻的那些框架值得我们格外的尊敬和关注,Jakarta C ...

最新文章

  1. c语言二叉树最小值,C语言递归之二叉树的最小深度
  2. Nlpir大数据知识图谱的落地指南
  3. SQLSERVER和ORACLE批量处理表名和字段名大写
  4. 步进电机无细分和20细分_细分网站导航会话
  5. android 检查 write_external_storage,android – 如何知道何时需要WRITE_EXTERNAL_STORAGE
  6. redis深度历险:核心原理与应用实践_送你一份Redis书单,以后使用缓存的问题不用再问我啦!...
  7. Linux安装SmartSVN及破解
  8. 内存管理--分发您的程序存储器
  9. Boost 连接库的命名含义
  10. centos7 卸载service服务
  11. 萤火虫小程序_漫展情报蛋趣携福利来萤火虫IDO漫展咯
  12. GDI 总结三: CImage类使用
  13. 酷家乐的 Istio 与 Knative 实践
  14. xml布局中实现文字下划线的效果
  15. 手机端和pc端浏览器兼容性问题
  16. saber 2.7.1 maven 配置
  17. 网页设计 1.HTML
  18. Vue教程_基础(一)
  19. xxx被声明为已否决
  20. Moz-css 大全

热门文章

  1. JAVA wait(), notify(),sleep详解
  2. Selenium WebDriver 与 iOS 自动化测试 (做了一些初步的工具对比)
  3. struts中采用注解配置Action
  4. 人民邮电出版社图灵公司征求《Windows Communication Foundation Unleashed》译者
  5. Cocoapods的安装及使用
  6. 老男孩Day3作业:工资管理系统
  7. Splay模板 1.0
  8. iOS开发之App间账号共享与SDK封装
  9. navigationBar设置透明度
  10. marquee标签制作轮播图