经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring Boot » 查看文章
Java GenericObjectPool 对象池化技术--SpringBoot sftp 连接池工具类
来源:cnblogs  作者:VipSoft  时间:2023/4/7 8:55:27  对本文有异议

Java BasePooledObjectFactory 对象池化技术

通常一个对象创建、销毁非常耗时的时候,我们不会频繁的创建和销毁它,而是考虑复用。复用对象的一种做法就是对象池,将创建好的对象放入池中维护起来,下次再用的时候直接拿池中已经创建好的对象继续用,这就是池化的思想。

Apache Commons Pool是一个对象池的框架,他提供了一整套用于实现对象池化的API。它提供了三种对象池:GenericKeyedObjectPool,SoftReferenceObjectPool和GenericObjectPool,其中GenericObjectPool是我们最常用的对象池,内部实现也最复杂。

GenericObjectPool

GenericObjectPool 是一个通用对象池框架,我们可以借助它实现一个健壮的对象池,UML图如下所示:
image

GenericObjectPool 实现了ObjectPool接口,而ObjectPool就是对象池的核心接口,它定义了一个对象池应该实现的行为。

  1. public interface ObjectPool<T> extends Closeable {
  2. /**
  3. * 从池中借走到一个对象
  4. */
  5. T borrowObject() throws Exception, NoSuchElementException, IllegalStateException;
  6. /**
  7. * 把对象归还给对象池
  8. */
  9. void returnObject(T var1) throws Exception;
  10. /**
  11. * 验证对象的有效性
  12. */
  13. void invalidateObject(T var1) throws Exception;
  14. /**
  15. * 往池中添加一个对象
  16. */
  17. void addObject() throws Exception, IllegalStateException, UnsupportedOperationException;
  18. /**
  19. * 返回对象池中有多少对象是空闲的,也就是能够被借走的对象的数量。
  20. */
  21. int getNumIdle();
  22. /**
  23. * 返回对象池中有对象对象是活跃的,也就是已经被借走的,在使用中的对象的数量。
  24. */
  25. int getNumActive();
  26. /**
  27. * 清理对象池。注意是清理不是清空,该方法要求的是,清理所有空闲对象,释放相关资源。
  28. */
  29. void clear() throws Exception, UnsupportedOperationException;
  30. /**
  31. * 关闭对象池。这个方法可以达到清空的效果,清理所有对象以及相关资源。
  32. */
  33. void close();
  34. }

BasePooledObjectFactory

Java BasePooledObjectFactory 对象池化技术

使用GenericObjectPool只需要创建一个对象工厂类,继承BasePooledObjectFactory并重写它的create()destroyObject()
如下文中的:SftpPool.java

  1. public interface PooledObjectFactory<T> {
  2. /**
  3. * 创建一个可由池提供服务的实例,并将其封装在由池管理的PooledObject中。
  4. */
  5. PooledObject<T> makeObject() throws Exception;
  6. /**
  7. * 销毁池不再需要的实例
  8. */
  9. void destroyObject(PooledObject<T> var1) throws Exception;
  10. /**
  11. * 确保实例可以安全地由池返回
  12. */
  13. boolean validateObject(PooledObject<T> var1);
  14. /**
  15. * 重新初始化池返回的实例
  16. */
  17. void activateObject(PooledObject<T> var1) throws Exception;
  18. /**
  19. * 取消初始化要返回到空闲对象池的实例
  20. */
  21. void passivateObject(PooledObject<T> var1) throws Exception;
  22. }

配置类GenericObjectPoolConfig

GenericObjectPoolConfig是封装GenericObject池配置的简单“结构”,此类不是线程安全的;它仅用于提供创建池时使用的属性。大多数情况,可以使用GenericObjectPoolConfig提供的默认参数就可以满足日常的需求。

工作原理流程

  1. 构造方法
    当我们执行构造方法时,主要工作就是创建了一个存储对象的LinkedList类型容器,也就是概念意义上的“池”
  2. 从对象池中获取对象
    获取池中的对象是通过borrowObject()命令,源码比较复杂,简单而言就是去LinkedList中获取一个对象,如果不存在的话,要调用构造方法中第一个参数Factory工厂类的makeObject()方法去创建一个对象再获取,获取到对象后要调用validateObject方法判断该对象是否是可用的,如果是可用的才拿去使用。LinkedList容器减一
  3. 归还对象到线程池
    简单而言就是先调用validateObject方法判断该对象是否是可用的,如果可用则归还到池中,LinkedList容器加一,如果是不可以的则调用destroyObject方法进行销毁

上面三步就是最简单的流程,由于取和还的流程步骤都在borrowObject和returnObject方法中固定的,所以我们只要重写Factory工厂类的makeObject()和validateObject以及destroyObject方法即可实现最简单的池的管理控制,通过构造方法传入该Factory工厂类对象则可以创建最简单的对象池管理类。这算是比较好的解耦设计模式,借和还的流程如下图所示:
image

使用Demo

  1. <dependency>
  2. <groupId>org.apache.commons</groupId>
  3. <artifactId>commons-pool2</artifactId>
  4. <version>2.7.0</version>
  5. </dependency>
  6. <!-- https://mvnrepository.com/artifact/com.jcraft/jsch -->
  7. <dependency>
  8. <groupId>com.jcraft</groupId>
  9. <artifactId>jsch</artifactId>
  10. <version>0.1.55</version>
  11. </dependency>
点击查看代码
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <parent>
  6. <artifactId>vipsoft-parent</artifactId>
  7. <groupId>com.vipsoft.boot</groupId>
  8. <version>1.0-SNAPSHOT</version>
  9. </parent>
  10. <modelVersion>4.0.0</modelVersion>
  11. <artifactId>vipsoft-sftp</artifactId>
  12. <version>1.0-SNAPSHOT</version>
  13. <dependencies>
  14. <dependency>
  15. <groupId>org.apache.commons</groupId>
  16. <artifactId>commons-pool2</artifactId>
  17. <version>2.7.0</version>
  18. </dependency>
  19. <!-- https://mvnrepository.com/artifact/com.jcraft/jsch -->
  20. <dependency>
  21. <groupId>com.jcraft</groupId>
  22. <artifactId>jsch</artifactId>
  23. <version>0.1.55</version>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.eclipse.paho</groupId>
  27. <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
  28. <version>1.2.5</version>
  29. </dependency>
  30. <dependency>
  31. <groupId>cn.hutool</groupId>
  32. <artifactId>hutool-all</artifactId>
  33. <version>5.3.6</version>
  34. </dependency>
  35. <dependency>
  36. <groupId>org.springframework.boot</groupId>
  37. <artifactId>spring-boot-starter-web</artifactId>
  38. </dependency>
  39. <dependency>
  40. <groupId>org.springframework.boot</groupId>
  41. <artifactId>spring-boot-starter-actuator</artifactId>
  42. </dependency>
  43. <dependency>
  44. <groupId>org.springframework.boot</groupId>
  45. <artifactId>spring-boot-starter-test</artifactId>
  46. <scope>test</scope>
  47. <exclusions>
  48. <exclusion>
  49. <groupId>org.junit.vintage</groupId>
  50. <artifactId>junit-vintage-engine</artifactId>
  51. </exclusion>
  52. </exclusions>
  53. </dependency>
  54. </dependencies>
  55. <build>
  56. <plugins>
  57. <plugin>
  58. <groupId>org.springframework.boot</groupId>
  59. <artifactId>spring-boot-maven-plugin</artifactId>
  60. </plugin>
  61. </plugins>
  62. </build>
  63. </project>

application.yaml

  1. server:
  2. port: 8088
  3. application:
  4. name: sftp Demo
  5. sftp:
  6. host: 172.16.3.88 # 服务器ip
  7. port: 22 # ssh端口
  8. username: root # 用户名
  9. password: root # 密码
  10. # 连接池参数
  11. pool:
  12. max-total: 10
  13. max-idle: 10
  14. min-idle: 5

SftpPoolException.java

  1. package com.vipsoft.sftp.exception;
  2. /**
  3. * sftp连接池异常
  4. */
  5. public class SftpPoolException extends RuntimeException {
  6. private static final long serialVersionUID = 1L;
  7. /**
  8. * Constructs a new runtime exception with {@code null} as its
  9. * detail message. The cause is not initialized, and may subsequently be
  10. * initialized by a call to {@link #initCause}.
  11. */
  12. public SftpPoolException() {
  13. }
  14. /**
  15. * Constructs a new runtime exception with the specified detail message.
  16. * The cause is not initialized, and may subsequently be initialized by a
  17. * call to {@link #initCause}.
  18. *
  19. * @param message the detail message. The detail message is saved for
  20. * later retrieval by the {@link #getMessage()} method.
  21. */
  22. public SftpPoolException(String message) {
  23. super(message);
  24. }
  25. /**
  26. * Constructs a new runtime exception with the specified detail message and
  27. * cause. <p>Note that the detail message associated with
  28. * {@code cause} is <i>not</i> automatically incorporated in
  29. * this runtime exception's detail message.
  30. *
  31. * @param message the detail message (which is saved for later retrieval
  32. * by the {@link #getMessage()} method).
  33. * @param cause the cause (which is saved for later retrieval by the
  34. * {@link #getCause()} method). (A <tt>null</tt> value is
  35. * permitted, and indicates that the cause is nonexistent or
  36. * unknown.)
  37. * @since 1.4
  38. */
  39. public SftpPoolException(String message, Throwable cause) {
  40. super(message, cause);
  41. }
  42. /**
  43. * Constructs a new runtime exception with the specified cause and a
  44. * detail message of <tt>(cause==null ? null : cause.toString())</tt>
  45. * (which typically contains the class and detail message of
  46. * <tt>cause</tt>). This constructor is useful for runtime exceptions
  47. * that are little more than wrappers for other throwables.
  48. *
  49. * @param cause the cause (which is saved for later retrieval by the
  50. * {@link #getCause()} method). (A <tt>null</tt> value is
  51. * permitted, and indicates that the cause is nonexistent or
  52. * unknown.)
  53. * @since 1.4
  54. */
  55. public SftpPoolException(Throwable cause) {
  56. super(cause);
  57. }
  58. /**
  59. * Constructs a new runtime exception with the specified detail
  60. * message, cause, suppression enabled or disabled, and writable
  61. * stack trace enabled or disabled.
  62. *
  63. * @param message the detail message.
  64. * @param cause the cause. (A {@code null} value is permitted,
  65. * and indicates that the cause is nonexistent or unknown.)
  66. * @param enableSuppression whether or not suppression is enabled
  67. * or disabled
  68. * @param writableStackTrace whether or not the stack trace should
  69. * be writable
  70. * @since 1.7
  71. */
  72. public SftpPoolException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
  73. super(message, cause, enableSuppression, writableStackTrace);
  74. }
  75. }

config

SftpConfig.java

  1. package com.vipsoft.sftp.config;
  2. import com.vipsoft.sftp.pool.SftpFactory;
  3. import com.vipsoft.sftp.pool.SftpPool;
  4. import com.vipsoft.sftp.utils.SftpUtil;
  5. import org.springframework.boot.context.properties.EnableConfigurationProperties;
  6. import org.springframework.context.annotation.Bean;
  7. import org.springframework.context.annotation.Configuration;
  8. @Configuration
  9. @EnableConfigurationProperties(SftpProperties.class)
  10. public class SftpConfig {
  11. // 工厂
  12. @Bean
  13. public SftpFactory sftpFactory(SftpProperties properties) {
  14. return new SftpFactory(properties);
  15. }
  16. // 连接池
  17. @Bean
  18. public SftpPool sftpPool(SftpFactory sftpFactory) {
  19. return new SftpPool(sftpFactory);
  20. }
  21. // 辅助类
  22. @Bean
  23. public SftpUtil sftpUtil(SftpPool sftpPool) {
  24. return new SftpUtil(sftpPool);
  25. }
  26. }

SftpProperties.java

  1. package com.vipsoft.sftp.config;
  2. import com.jcraft.jsch.ChannelSftp;
  3. import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
  4. import org.springframework.boot.context.properties.ConfigurationProperties;
  5. @ConfigurationProperties(prefix = "sftp")
  6. public class SftpProperties {
  7. private String host;
  8. private int port = 22;
  9. private String username = "root";
  10. private String password = "root";
  11. private Pool pool = new Pool();
  12. public String getHost() {
  13. return host;
  14. }
  15. public void setHost(String host) {
  16. this.host = host;
  17. }
  18. public int getPort() {
  19. return port;
  20. }
  21. public void setPort(int port) {
  22. this.port = port;
  23. }
  24. public String getUsername() {
  25. return username;
  26. }
  27. public void setUsername(String username) {
  28. this.username = username;
  29. }
  30. public String getPassword() {
  31. return password;
  32. }
  33. public void setPassword(String password) {
  34. this.password = password;
  35. }
  36. public Pool getPool() {
  37. return pool;
  38. }
  39. public void setPool(Pool pool) {
  40. this.pool = pool;
  41. }
  42. public static class Pool extends GenericObjectPoolConfig<ChannelSftp> {
  43. private int maxTotal = DEFAULT_MAX_TOTAL;
  44. private int maxIdle = DEFAULT_MAX_IDLE;
  45. private int minIdle = DEFAULT_MIN_IDLE;
  46. public Pool() {
  47. super();
  48. }
  49. @Override
  50. public int getMaxTotal() {
  51. return maxTotal;
  52. }
  53. @Override
  54. public void setMaxTotal(int maxTotal) {
  55. this.maxTotal = maxTotal;
  56. }
  57. @Override
  58. public int getMaxIdle() {
  59. return maxIdle;
  60. }
  61. @Override
  62. public void setMaxIdle(int maxIdle) {
  63. this.maxIdle = maxIdle;
  64. }
  65. @Override
  66. public int getMinIdle() {
  67. return minIdle;
  68. }
  69. @Override
  70. public void setMinIdle(int minIdle) {
  71. this.minIdle = minIdle;
  72. }
  73. }
  74. }

Pool

SftpFactory.java

  1. package com.vipsoft.sftp.pool;
  2. import com.jcraft.jsch.ChannelSftp;
  3. import com.jcraft.jsch.JSch;
  4. import com.jcraft.jsch.JSchException;
  5. import com.jcraft.jsch.Session;
  6. import com.vipsoft.sftp.config.SftpProperties;
  7. import com.vipsoft.sftp.exception.SftpPoolException;
  8. import org.apache.commons.pool2.BasePooledObjectFactory;
  9. import org.apache.commons.pool2.PooledObject;
  10. import org.apache.commons.pool2.impl.DefaultPooledObject;
  11. import org.slf4j.Logger;
  12. import org.slf4j.LoggerFactory;
  13. import java.util.Properties;
  14. public class SftpFactory extends BasePooledObjectFactory<ChannelSftp> {
  15. private final Logger logger = LoggerFactory.getLogger(this.getClass());
  16. private SftpProperties properties;
  17. public SftpProperties getProperties() {
  18. return properties;
  19. }
  20. public void setProperties(SftpProperties properties) {
  21. this.properties = properties;
  22. }
  23. public SftpFactory(SftpProperties properties) {
  24. this.properties = properties;
  25. }
  26. @Override
  27. public ChannelSftp create() {
  28. try {
  29. JSch jsch = new JSch();
  30. Session sshSession = jsch.getSession(properties.getUsername(), properties.getHost(), properties.getPort());
  31. sshSession.setPassword(properties.getPassword());
  32. Properties sshConfig = new Properties();
  33. sshConfig.put("StrictHostKeyChecking", "no");
  34. sshSession.setConfig(sshConfig);
  35. sshSession.connect();
  36. ChannelSftp channel = (ChannelSftp) sshSession.openChannel("sftp");
  37. channel.connect();
  38. return channel;
  39. } catch (JSchException e) {
  40. throw new SftpPoolException("连接sfpt失败", e);
  41. }
  42. }
  43. @Override
  44. public PooledObject<ChannelSftp> wrap(ChannelSftp channelSftp) {
  45. return new DefaultPooledObject<>(channelSftp);
  46. }
  47. // 销毁对象
  48. @Override
  49. public void destroyObject(PooledObject<ChannelSftp> p) {
  50. ChannelSftp channelSftp = p.getObject();
  51. channelSftp.disconnect();
  52. }
  53. }

SftpPool.java

  1. package com.vipsoft.sftp.pool;
  2. import com.jcraft.jsch.ChannelSftp;
  3. import org.apache.commons.pool2.impl.GenericObjectPool;
  4. public class SftpPool<T> extends GenericObjectPool<ChannelSftp> {
  5. public SftpPool(SftpFactory factory) {
  6. super(factory,factory.getProperties().getPool());
  7. }
  8. /**
  9. * 获取一个sftp连接对象
  10. * @return sftp连接对象
  11. */
  12. @Override
  13. public ChannelSftp borrowObject() throws Exception {
  14. return super.borrowObject();
  15. }
  16. /**
  17. * 归还一个sftp连接对象
  18. * @param channelSftp sftp连接对象
  19. */
  20. @Override
  21. public void returnObject(ChannelSftp channelSftp) {
  22. if (channelSftp!=null) {
  23. super.returnObject(channelSftp);
  24. }
  25. }
  26. }

Utils

ByteUtil.java

  1. package com.vipsoft.sftp.utils;
  2. import com.jcraft.jsch.ChannelSftp;
  3. import com.jcraft.jsch.SftpException;
  4. import com.vipsoft.sftp.exception.SftpPoolException;
  5. import com.vipsoft.sftp.pool.SftpPool;
  6. import java.io.InputStream;
  7. public class SftpUtil {
  8. private SftpPool pool;
  9. public SftpUtil(SftpPool pool) {
  10. this.pool = pool;
  11. }
  12. /**
  13. * 下载文件
  14. *
  15. * @param dir 远程目录
  16. * @param name 远程文件名
  17. * @return 文件字节数组
  18. */
  19. public byte[] download(String dir, String name) {
  20. ChannelSftp sftp = null;
  21. try {
  22. sftp = pool.borrowObject();
  23. sftp.cd(dir);
  24. InputStream in = sftp.get(name);
  25. return ByteUtil.inputStreamToByteArray(in);
  26. } catch (Exception e) {
  27. throw new SftpPoolException("sftp下载文件出错", e);
  28. } finally {
  29. pool.returnObject(sftp);
  30. }
  31. }
  32. /**
  33. * 上传文件
  34. *
  35. * @param dir 远程目录
  36. * @param name 远程文件名
  37. * @param in 输入流
  38. */
  39. public void upload(String dir, String name, InputStream in) {
  40. ChannelSftp sftp = null;
  41. try {
  42. sftp = pool.borrowObject();
  43. mkdirs(sftp, dir);
  44. sftp.cd(dir);
  45. sftp.put(in, name);
  46. } catch (Exception e) {
  47. throw new SftpPoolException("sftp上传文件出错", e);
  48. } finally {
  49. pool.returnObject(sftp);
  50. }
  51. }
  52. /**
  53. * 删除文件
  54. *
  55. * @param dir 远程目录
  56. * @param name 远程文件名
  57. */
  58. public void delete(String dir, String name) {
  59. ChannelSftp sftp = null;
  60. try {
  61. sftp = pool.borrowObject();
  62. sftp.cd(dir);
  63. sftp.rm(name);
  64. } catch (Exception e) {
  65. throw new SftpPoolException("sftp删除文件出错", e);
  66. } finally {
  67. pool.returnObject(sftp);
  68. }
  69. }
  70. /**
  71. * 递归创建多级目录
  72. *
  73. * @param dir 多级目录
  74. */
  75. private void mkdirs(ChannelSftp sftp, String dir) {
  76. String[] folders = dir.split("/");
  77. try {
  78. sftp.cd("/");
  79. for (String folder : folders) {
  80. if (folder.length() > 0) {
  81. try {
  82. sftp.cd(folder);
  83. } catch (Exception e) {
  84. sftp.mkdir(folder);
  85. sftp.cd(folder);
  86. }
  87. }
  88. }
  89. } catch (SftpException e) {
  90. throw new SftpPoolException("sftp创建目录出错", e);
  91. }
  92. }
  93. }

Test

SftpTest.java

  1. package com.vipsoft.sftp;
  2. import com.vipsoft.sftp.utils.SftpUtil;
  3. import org.junit.jupiter.api.Test;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.boot.test.context.SpringBootTest;
  6. @SpringBootTest
  7. public class SftpTest {
  8. @Autowired
  9. private SftpUtil sftpUtil;
  10. @Test
  11. void downloadTest() {
  12. byte[] dockerfiles = sftpUtil.download("/opt/demo/", "Dockerfile");
  13. System.out.println("FileSize =>" + dockerfiles.length);
  14. }
  15. }

image

原文链接:https://www.cnblogs.com/vipsoft/p/17272728.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号