亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么快速實現一個連接池

發布時間:2021-06-12 10:47:47 來源:億速云 閱讀:231 作者:小新 欄目:web開發

這篇文章主要介紹怎么快速實現一個連接池,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!

在實際工作中,我們經常會用到各種連接池,例如:連接 FTP  服務器的連接數有限,需要建立一個連接池;連接數據庫的連接數有限,需要建立一個連接池。那我們如何去快速實現一個連接池呢?

無論是 FTP  連接池,還是數據庫連接池,我們會發現它們都有相同的地方,它們都需要:生命周期管理、連接創建管理等等。如果我們從零開始去實現這些功能,那我們要耗費的時間就很長了!那有沒有一個通用的庫可以快速實現一個線程池呢?

得益于 Java 完善的生態,前人們針對這種需要開發了一個通用庫:Apache Commons Pool(下文簡稱 ACP)。本質上來說,ACP  庫提供的是管理對象池的通用能力,當然也可以用來管理連接池了!

什么是 ACP?

ACP 庫提供了一整套用于實現對象池化的 API,以及若干種各具特色的對象池實現。目前最常用的版本是 2.0 版本,相對于 1.x  版本而言,并不是簡單升級。2.0 版本是對象池實現的完全重寫,顯著的提升了性能和可伸縮性,并且包含可靠的實例跟蹤和池監控。

Apache Commons Pool 的官網地址為:Pool – Overview,想翻找相關文檔資料,到這里去是最權威、最全面的。

如何使用 ACP?

要使用 ACP 實現一個線程池,首先需要先引入 ACP 的依賴包,這里以 Maven 為例。

<dependency>  <groupId>org.apache.commons</groupId>  <artifactId>commons-pool2</artifactId>  <version>2.0</version> </dependency>

要使用 ACP 實現一個對象池,大致可以分為三個步驟:

  • 創建對象工廠:告訴 ACP 如何創建你要的對象。

  • 創建對象池:告訴 ACP 你想創建一個怎樣的對象池。

  • 使用對象池:ACP 告訴你如何使用你的對象。

創建對象工廠

對象工廠告訴 ACP,它應該如何去創建、激活、鈍化、銷毀你的對象。創建對象工廠非常簡單,只需要實現 ACP 的 PooledObjectFactory  接口即可。PooledObjectFactory 接口的定義如下:

public interface PooledObjectFactory<T> {   PooledObject<T> makeObject() throws Exception;   void destroyObject(PooledObject<T> p) throws Exception;   boolean validateObject(PooledObject<T> p);   void activateObject(PooledObject<T> p) throws Exception;   void passivateObject(PooledObject<T> p) throws Exception; }

但更多情況下,我們會繼承 BasePooledObjectFactory 類來實現對象工廠。因為 BasePooledObjectFactory 類是  PooledObjectFactory 的基礎實現類,使用它可以幫我們省了很多麻煩。通過繼承這個抽象類,我們只需要實現兩個方法:create() 和  wrap() 方法。

// 告訴 ACP 如何創建對象 public abstract T create() throws Exception; // 定義你要返回的對象 public abstract PooledObject<T> wrap(T obj);

create() 方法定義你的對象初始化過程,最后將初始化完成的對象返回。例如你想定義一個 SFTP 的連接,那么你首先需要定義一個 JSch  對象,之后設置賬號密碼,之后連接服務器,最后返回一個 ChannelSftp 對象。

public ChannelSftp create() {     // SFTP 連接的創建過程 }

wrap() 方法定義你要返回的對象,對于一個 SFTP 的連接池來說,其實就是一個 ChannelSftp 對象。一般情況下可以使用類  DefaultPooledObject 替代,參考實現如下:

@Override public PooledObject<Foo> wrap(Foo foo) {     return new DefaultPooledObject<Foo>(foo); }

創建對象池

創建好對象工廠之后,ACP 已經知道你需要的對象如何創建了。那么接下來,你需要根據你的實際需要,去創建一個對象池。在 ACP 中,我們通過  GenericObjectPool 以及 GenericObjectPoolConfig 來創建一個對象池。

// 聲明一個對象池 private GenericObjectPool<ChannelSftp> sftpConnectPool;  // 設置連接池配置         GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();         poolConfig.setEvictionPolicyClassName("tech.shuyi.javacodechip.acp.SftpEvictionPolicy");         poolConfig.setBlockWhenExhausted(true);         poolConfig.setJmxEnabled(false);         poolConfig.setMaxWaitMillis(1000 * 10);         poolConfig.setTimeBetweenEvictionRunsMillis(60 * 1000);         poolConfig.setMinEvictableIdleTimeMillis(20 * 1000);         poolConfig.setTestWhileIdle(true);         poolConfig.setTestOnReturn(true);         poolConfig.setTestOnBorrow(true);         poolConfig.setMaxTotal(3);         // 設置拋棄策略         AbandonedConfig abandonedConfig = new AbandonedConfig();         abandonedConfig.setRemoveAbandonedOnMaintenance(true);         abandonedConfig.setRemoveAbandonedOnBorrow(true);         this.sftpConnectPool = new GenericObjectPool<>(sftpConnectFactory, poolConfig, abandonedConfig);

在上面創建 SFTP  連接池的代碼中,我們配置了一些線程池的參數以及設置了拋棄策略。拋棄策略是非常重要的,如果沒有設置拋棄策略,那么會拿到失效的連接從而導致獲取文件失敗。拋棄策略是通過  poolConfig.setEvictionPolicyClassName 來設置的,我們這里設置的是 SftpEvictionPolicy  類,其代碼內容如下:

@Slf4j @Component public class SftpEvictionPolicy implements EvictionPolicy<com.jcraft.jsch.ChannelSftp> {     @Override     public boolean evict(EvictionConfig config, PooledObject<com.jcraft.jsch.ChannelSftp> underTest, int idleCount) {         try {             // 連接失效時進行驅逐             if (!underTest.getObject().isConnected()) {                 log.warn("connect time out, evict the connection. time={}",System.currentTimeMillis() - underTest.getLastReturnTime());                 return true;             }         }catch (Exception e){             return true;         }         return false;     } }

看到這里,創建線程池的代碼就結束了,SftpConnectPool 文件的全部內容如下:

@Slf4j public class SftpConnectPool {      private GenericObjectPool<ChannelSftp> sftpConnectPool;      public SftpConnectPool(SftpConnectFactory sftpConnectFactory) {         // 設置連接池配置         GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();         poolConfig.setEvictionPolicyClassName("tech.shuyi.javacodechip.acp.SftpEvictionPolicy");         poolConfig.setBlockWhenExhausted(true);         poolConfig.setJmxEnabled(false);         poolConfig.setMaxWaitMillis(1000 * 10);         poolConfig.setTimeBetweenEvictionRunsMillis(60 * 1000);         poolConfig.setMinEvictableIdleTimeMillis(20 * 1000);         poolConfig.setTestWhileIdle(true);         poolConfig.setTestOnReturn(true);         poolConfig.setTestOnBorrow(true);         poolConfig.setMaxTotal(3);         // 設置拋棄策略         AbandonedConfig abandonedConfig = new AbandonedConfig();         abandonedConfig.setRemoveAbandonedOnMaintenance(true);         abandonedConfig.setRemoveAbandonedOnBorrow(true);         this.sftpConnectPool = new GenericObjectPool<>(sftpConnectFactory, poolConfig, abandonedConfig);     }      public ChannelSftp borrowObject() {         try {             return sftpConnectPool.borrowObject();         } catch (Exception e) {             log.error("borrowObject error", e);             return null;         }     }      public void returnObject(ChannelSftp channelSftp) {         if (channelSftp!=null) {             sftpConnectPool.returnObject(channelSftp);         }     } }

為了方便使用,我還增加了 borrowObject 和 returnObject 方法,但這兩個并不是必須的。在這兩個方法中,我們分別調用了  GenericObjectPool 類的 borrowObject 方法和 returnObject 方法。這正是 ACP  提供的、使用線程池對象的方法,先借一個對象,之后歸還對象。

注:其實在這一步,已經包含了對象池的使用了。但實際使用的時候,我們經常是將對象池的聲明與使用放在同一個類中,因此為了講解方便,這里沒有分開。因此下文的使用對象池,本質上是對對象池做進一步封裝。

使用對象池

到這里我們的 SFTP 對象池就已經創建完畢了,是不是非常簡單呢!但在實際的工作中,我們通常會在這基礎上,做一些封裝。對于我們這次的 SFTP  連接池來說,我們會對外直接提供下載文件的服務,將 SFTP 對象池進一步封裝起來,不需要關心怎么獲取文件。

public class SftpFileHelper {      @Autowired     private SftpConnectPool sftpConnectPool;      public void download(String dir, String file, String saveUrl)throws IOException {         ChannelSftp sftp = sftpConnectPool.borrowObject();         log.info("begin to download file, dir={}, file={}, saveUrl={}", dir, file, saveUrl);         try {             if (!StringUtils.isEmpty(dir)) {                 sftp.cd(dir);             }             File downloadFile = new File(saveUrl);             sftp.get(file, new FileOutputStream(downloadFile));         }catch (Exception e){             log.warn("下載文件失敗", e);         }finally {             sftpConnectPool.returnObject(sftp);         }         log.info("file:{} is download successful", file);     } }

最后我們寫一個測試用例來試一試,是否能正常下載文件。

@RunWith(SpringRunner.class) @SpringBootTest @Slf4j public class SftpFileHelperTest {      @Autowired     private SftpFileHelper sftpFileHelper;      @Test     public void testDownloadFtpFile() throws Exception {         sftpFileHelper.download("dir", "fileName", "fileName");     } }

沒有意外的話,你會看到一條綠線,文件已經被成功下載了!

以上是“怎么快速實現一個連接池”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

海林市| 贵定县| 德兴市| 施甸县| 双牌县| 浏阳市| 如皋市| 赞皇县| 城固县| 星子县| 丹东市| 沙坪坝区| 乡宁县| 甘谷县| 保康县| 华阴市| 莒南县| 廉江市| 舟曲县| 龙川县| 芮城县| 桂林市| 汨罗市| 重庆市| 大方县| 漾濞| 澎湖县| 余干县| 凉城县| 枣阳市| 蒙山县| 宜都市| 廊坊市| 乌什县| 双柏县| 韶山市| 出国| 桃江县| 新源县| 平潭县| 湄潭县|