java basepooledobjectfactory 对象池化技术
通常一个对象创建、销毁非常耗时的时候,我们不会频繁的创建和销毁它,而是考虑复用。复用对象的一种做法就是对象池,将创建好的对象放入池中维护起来,下次再用的时候直接拿池中已经创建好的对象继续用,这就是池化的思想。
apache commons pool是一个对象池的框架,他提供了一整套用于实现对象池化的api。它提供了三种对象池:generickeyedobjectpool,softreferenceobjectpool和genericobjectpool,其中genericobjectpool是我们最常用的对象池,内部实现也最复杂。
genericobjectpoolgenericobjectpool 是一个通用对象池框架,我们可以借助它实现一个健壮的对象池,uml图如下所示:
genericobjectpool 实现了objectpool接口,而objectpool就是对象池的核心接口,它定义了一个对象池应该实现的行为。
public interface objectpool<t> extends closeable { /** * 从池中借走到一个对象 */ t borrowobject() throws exception, nosuchelementexception, illegalstateexception; /** * 把对象归还给对象池 */ void returnobject(t var1) throws exception; /** * 验证对象的有效性 */ void invalidateobject(t var1) throws exception; /** * 往池中添加一个对象 */ void addobject() throws exception, illegalstateexception, unsupportedoperationexception; /** * 返回对象池中有多少对象是空闲的,也就是能够被借走的对象的数量。 */ int getnumidle(); /** * 返回对象池中有对象对象是活跃的,也就是已经被借走的,在使用中的对象的数量。 */ int getnumactive(); /** * 清理对象池。注意是清理不是清空,该方法要求的是,清理所有空闲对象,释放相关资源。 */ void clear() throws exception, unsupportedoperationexception; /** * 关闭对象池。这个方法可以达到清空的效果,清理所有对象以及相关资源。 */ void close();}
basepooledobjectfactoryjava basepooledobjectfactory 对象池化技术
使用genericobjectpool只需要创建一个对象工厂类,继承basepooledobjectfactory并重写它的create()和destroyobject()。
如下文中的:sftppool.java
public interface pooledobjectfactory<t> { /** * 创建一个可由池提供服务的实例,并将其封装在由池管理的pooledobject中。 */ pooledobject<t> makeobject() throws exception; /** * 销毁池不再需要的实例 */ void destroyobject(pooledobject<t> var1) throws exception; /** * 确保实例可以安全地由池返回 */ boolean validateobject(pooledobject<t> var1); /** * 重新初始化池返回的实例 */ void activateobject(pooledobject<t> var1) throws exception; /** * 取消初始化要返回到空闲对象池的实例 */ void passivateobject(pooledobject<t> var1) throws exception;}
配置类genericobjectpoolconfiggenericobjectpoolconfig是封装genericobject池配置的简单“结构”,此类不是线程安全的;它仅用于提供创建池时使用的属性。大多数情况,可以使用genericobjectpoolconfig提供的默认参数就可以满足日常的需求。
工作原理流程
构造方法
当我们执行构造方法时,主要工作就是创建了一个存储对象的linkedlist类型容器,也就是概念意义上的“池”
从对象池中获取对象
获取池中的对象是通过borrowobject()命令,源码比较复杂,简单而言就是去linkedlist中获取一个对象,如果不存在的话,要调用构造方法中第一个参数factory工厂类的makeobject()方法去创建一个对象再获取,获取到对象后要调用validateobject方法判断该对象是否是可用的,如果是可用的才拿去使用。linkedlist容器减一
归还对象到线程池
简单而言就是先调用validateobject方法判断该对象是否是可用的,如果可用则归还到池中,linkedlist容器加一,如果是不可以的则调用destroyobject方法进行销毁
上面三步就是最简单的流程,由于取和还的流程步骤都在borrowobject和returnobject方法中固定的,所以我们只要重写factory工厂类的makeobject()和validateobject以及destroyobject方法即可实现最简单的池的管理控制,通过构造方法传入该factory工厂类对象则可以创建最简单的对象池管理类。这算是比较好的解耦设计模式,借和还的流程如下图所示:
使用demo<dependency> <groupid>org.apache.commons</groupid> <artifactid>commons-pool2</artifactid> <version>2.7.0</version></dependency><!-- https://mvnrepository.com/artifact/com.jcraft/jsch --><dependency> <groupid>com.jcraft</groupid> <artifactid>jsch</artifactid> <version>0.1.55</version></dependency>
<?xml version="1.0" encoding="utf-8"?><project xmlns="http://maven.apache.org/pom/4.0.0" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="http://maven.apache.org/pom/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactid>vipsoft-parent</artifactid> <groupid>com.vipsoft.boot</groupid> <version>1.0-snapshot</version> </parent> <modelversion>4.0.0</modelversion> <artifactid>vipsoft-sftp</artifactid> <version>1.0-snapshot</version> <dependencies> <dependency> <groupid>org.apache.commons</groupid> <artifactid>commons-pool2</artifactid> <version>2.7.0</version> </dependency> <!-- https://mvnrepository.com/artifact/com.jcraft/jsch --> <dependency> <groupid>com.jcraft</groupid> <artifactid>jsch</artifactid> <version>0.1.55</version> </dependency> <dependency> <groupid>org.eclipse.paho</groupid> <artifactid>org.eclipse.paho.client.mqttv3</artifactid> <version>1.2.5</version> </dependency> <dependency> <groupid>cn.hutool</groupid> <artifactid>hutool-all</artifactid> <version>5.3.6</version> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-actuator</artifactid> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-test</artifactid> <scope>test</scope> <exclusions> <exclusion> <groupid>org.junit.vintage</groupid> <artifactid>junit-vintage-engine</artifactid> </exclusion> </exclusions> </dependency> </dependencies> <build> <plugins> <plugin> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-maven-plugin</artifactid> </plugin> </plugins> </build></project>
application.yaml
server: port: 8088 application: name: sftp demosftp: host: 172.16.3.88 # 服务器ip port: 22 # ssh端口 username: root # 用户名 password: root # 密码 # 连接池参数 pool: max-total: 10 max-idle: 10 min-idle: 5
sftppoolexception.java
package com.vipsoft.sftp.exception;/** * sftp连接池异常 */public class sftppoolexception extends runtimeexception { private static final long serialversionuid = 1l; /** * constructs a new runtime exception with {@code null} as its * detail message. the cause is not initialized, and may subsequently be * initialized by a call to {@link #initcause}. */ public sftppoolexception() { } /** * constructs a new runtime exception with the specified detail message. * the cause is not initialized, and may subsequently be initialized by a * call to {@link #initcause}. * * @param message the detail message. the detail message is saved for * later retrieval by the {@link #getmessage()} method. */ public sftppoolexception(string message) { super(message); } /** * constructs a new runtime exception with the specified detail message and * cause. <p>note that the detail message associated with * {@code cause} is <i>not</i> automatically incorporated in * this runtime exception's detail message. * * @param message the detail message (which is saved for later retrieval * by the {@link #getmessage()} method). * @param cause the cause (which is saved for later retrieval by the * {@link #getcause()} method). (a <tt>null</tt> value is * permitted, and indicates that the cause is nonexistent or * unknown.) * @since 1.4 */ public sftppoolexception(string message, throwable cause) { super(message, cause); } /** * constructs a new runtime exception with the specified cause and a * detail message of <tt>(cause==null ? null : cause.tostring())</tt> * (which typically contains the class and detail message of * <tt>cause</tt>). this constructor is useful for runtime exceptions * that are little more than wrappers for other throwables. * * @param cause the cause (which is saved for later retrieval by the * {@link #getcause()} method). (a <tt>null</tt> value is * permitted, and indicates that the cause is nonexistent or * unknown.) * @since 1.4 */ public sftppoolexception(throwable cause) { super(cause); } /** * constructs a new runtime exception with the specified detail * message, cause, suppression enabled or disabled, and writable * stack trace enabled or disabled. * * @param message the detail message. * @param cause the cause. (a {@code null} value is permitted, * and indicates that the cause is nonexistent or unknown.) * @param enablesuppression whether or not suppression is enabled * or disabled * @param writablestacktrace whether or not the stack trace should * be writable * @since 1.7 */ public sftppoolexception(string message, throwable cause, boolean enablesuppression, boolean writablestacktrace) { super(message, cause, enablesuppression, writablestacktrace); }}
configsftpconfig.java
package com.vipsoft.sftp.config;import com.vipsoft.sftp.pool.sftpfactory;import com.vipsoft.sftp.pool.sftppool;import com.vipsoft.sftp.utils.sftputil;import org.springframework.boot.context.properties.enableconfigurationproperties;import org.springframework.context.annotation.bean;import org.springframework.context.annotation.configuration;@configuration@enableconfigurationproperties(sftpproperties.class)public class sftpconfig { // 工厂 @bean public sftpfactory sftpfactory(sftpproperties properties) { return new sftpfactory(properties); } // 连接池 @bean public sftppool sftppool(sftpfactory sftpfactory) { return new sftppool(sftpfactory); } // 辅助类 @bean public sftputil sftputil(sftppool sftppool) { return new sftputil(sftppool); }}
sftpproperties.java
package com.vipsoft.sftp.config;import com.jcraft.jsch.channelsftp;import org.apache.commons.pool2.impl.genericobjectpoolconfig;import org.springframework.boot.context.properties.configurationproperties;@configurationproperties(prefix = "sftp")public class sftpproperties { private string host; private int port = 22; private string username = "root"; private string password = "root"; private pool pool = new pool(); 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 pool getpool() { return pool; } public void setpool(pool pool) { this.pool = pool; } public static class pool extends genericobjectpoolconfig<channelsftp> { private int maxtotal = default_max_total; private int maxidle = default_max_idle; private int minidle = default_min_idle; public pool() { super(); } @override public int getmaxtotal() { return maxtotal; } @override public void setmaxtotal(int maxtotal) { this.maxtotal = maxtotal; } @override public int getmaxidle() { return maxidle; } @override public void setmaxidle(int maxidle) { this.maxidle = maxidle; } @override public int getminidle() { return minidle; } @override public void setminidle(int minidle) { this.minidle = minidle; } }}
poolsftpfactory.java
package com.vipsoft.sftp.pool;import com.jcraft.jsch.channelsftp;import com.jcraft.jsch.jsch;import com.jcraft.jsch.jschexception;import com.jcraft.jsch.session;import com.vipsoft.sftp.config.sftpproperties;import com.vipsoft.sftp.exception.sftppoolexception;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.util.properties;public class sftpfactory extends basepooledobjectfactory<channelsftp> { private final logger logger = loggerfactory.getlogger(this.getclass()); private sftpproperties properties; public sftpproperties getproperties() { return properties; } public void setproperties(sftpproperties properties) { this.properties = properties; } public sftpfactory(sftpproperties properties) { this.properties = properties; } @override public channelsftp create() { try { jsch jsch = new jsch(); session sshsession = jsch.getsession(properties.getusername(), properties.gethost(), properties.getport()); sshsession.setpassword(properties.getpassword()); properties sshconfig = new properties(); sshconfig.put("stricthostkeychecking", "no"); sshsession.setconfig(sshconfig); sshsession.connect(); channelsftp channel = (channelsftp) sshsession.openchannel("sftp"); channel.connect(); return channel; } catch (jschexception e) { throw new sftppoolexception("连接sfpt失败", e); } } @override public pooledobject<channelsftp> wrap(channelsftp channelsftp) { return new defaultpooledobject<>(channelsftp); } // 销毁对象 @override public void destroyobject(pooledobject<channelsftp> p) { channelsftp channelsftp = p.getobject(); channelsftp.disconnect(); }}
sftppool.java
package com.vipsoft.sftp.pool;import com.jcraft.jsch.channelsftp;import org.apache.commons.pool2.impl.genericobjectpool;public class sftppool<t> extends genericobjectpool<channelsftp> { public sftppool(sftpfactory factory) { super(factory,factory.getproperties().getpool()); } /** * 获取一个sftp连接对象 * @return sftp连接对象 */ @override public channelsftp borrowobject() throws exception { return super.borrowobject(); } /** * 归还一个sftp连接对象 * @param channelsftp sftp连接对象 */ @override public void returnobject(channelsftp channelsftp) { if (channelsftp!=null) { super.returnobject(channelsftp); } }}
utilsbyteutil.java
package com.vipsoft.sftp.utils;import com.jcraft.jsch.channelsftp;import com.jcraft.jsch.sftpexception;import com.vipsoft.sftp.exception.sftppoolexception;import com.vipsoft.sftp.pool.sftppool;import java.io.inputstream;public class sftputil { private sftppool pool; public sftputil(sftppool pool) { this.pool = pool; } /** * 下载文件 * * @param dir 远程目录 * @param name 远程文件名 * @return 文件字节数组 */ public byte[] download(string dir, string name) { channelsftp sftp = null; try { sftp = pool.borrowobject(); sftp.cd(dir); inputstream in = sftp.get(name); return byteutil.inputstreamtobytearray(in); } catch (exception e) { throw new sftppoolexception("sftp下载文件出错", e); } finally { pool.returnobject(sftp); } } /** * 上传文件 * * @param dir 远程目录 * @param name 远程文件名 * @param in 输入流 */ public void upload(string dir, string name, inputstream in) { channelsftp sftp = null; try { sftp = pool.borrowobject(); mkdirs(sftp, dir); sftp.cd(dir); sftp.put(in, name); } catch (exception e) { throw new sftppoolexception("sftp上传文件出错", e); } finally { pool.returnobject(sftp); } } /** * 删除文件 * * @param dir 远程目录 * @param name 远程文件名 */ public void delete(string dir, string name) { channelsftp sftp = null; try { sftp = pool.borrowobject(); sftp.cd(dir); sftp.rm(name); } catch (exception e) { throw new sftppoolexception("sftp删除文件出错", e); } finally { pool.returnobject(sftp); } } /** * 递归创建多级目录 * * @param dir 多级目录 */ private void mkdirs(channelsftp sftp, string dir) { string[] folders = dir.split("/"); try { sftp.cd("/"); for (string folder : folders) { if (folder.length() > 0) { try { sftp.cd(folder); } catch (exception e) { sftp.mkdir(folder); sftp.cd(folder); } } } } catch (sftpexception e) { throw new sftppoolexception("sftp创建目录出错", e); } }}
testsftptest.java
package com.vipsoft.sftp;import com.vipsoft.sftp.utils.sftputil;import org.junit.jupiter.api.test;import org.springframework.beans.factory.annotation.autowired;import org.springframework.boot.test.context.springboottest;@springboottestpublic class sftptest { @autowired private sftputil sftputil; @test void downloadtest() { byte[] dockerfiles = sftputil.download("/opt/demo/", "dockerfile"); system.out.println("filesize =>" + dockerfiles.length); }}
以上就是如何使用java genericobjectpool对象池化技术的详细内容。