亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

封裝一個(gè)FTP工具類

LuDongWei / 2737人閱讀

摘要:封裝一個(gè)操作工具類概述前人的代碼中把操作和業(yè)務(wù)邏輯實(shí)現(xiàn)耦合在一起,據(jù)說(shuō)經(jīng)過(guò)多次的修改,在性能表現(xiàn)方面已經(jīng)非??孔V。連接對(duì)象池使用對(duì)象池管理方式需要提供一個(gè)工廠類,管理對(duì)象的生成銷毀等。

封裝一個(gè)FTP操作工具類 概述

前人的代碼中把FTP操作和業(yè)務(wù)邏輯實(shí)現(xiàn)耦合在一起,據(jù)說(shuō)經(jīng)過(guò)多次的修改,在性能表現(xiàn)方面已經(jīng)非常靠譜。
在原來(lái)的代碼中可以看到使用了commons-net進(jìn)行FTP操作,使用commons-pool對(duì)象池方式管理FTP連接,
完成了多線程下載和上傳的功能,本次的修改只是把耦合的地方剝離開(kāi)來(lái)。

FTP連接對(duì)象池

使用apache commons pool對(duì)象池管理方式需要提供一個(gè)工廠類,管理對(duì)象的生成銷毀等。
需要實(shí)現(xiàn)如下方法,

PooledObject makeObject(K key) throws Exception;
void destroyObject(K key, PooledObject p) throws Exception;
boolean validateObject(K key, PooledObject p);

apache commons pool提供了一個(gè)帶泛型的接口KeyedPooledObjectFactory
需要繼承實(shí)現(xiàn)類提供對(duì)象工廠的key類型,及要生產(chǎn)的對(duì)象類型,key可以是一個(gè)類,包含F(xiàn)TP的IP
,端口,用戶名密碼等屬性組成,目的是區(qū)分不同的FTP連接,

public class FtpClientConfig {
    
    private String host;
    private int port;
    private String username;
    private String password;
...
}

這里要生產(chǎn)的對(duì)象類型當(dāng)然是FTPClient了,所以我們的工廠類是這樣的,

public class FtpClientFactory implements KeyedPooledObjectFactory{
...
}

相應(yīng)的,我們提供一個(gè)對(duì)象池的實(shí)現(xiàn),其實(shí)很簡(jiǎn)單

public class FtpClientPool extends GenericKeyedObjectPool  {

    public FtpClientPool(FtpClientFactory factory, FtpPoolConfig config) {
        super(factory, config);
    }

}

構(gòu)造方法的參數(shù)就是我們提供的對(duì)象工廠FtpClientFactoryFtpPoolConfigFtpPoolConfig

public class FtpPoolConfig extends GenericKeyedObjectPoolConfig{
    public FtpPoolConfig() {
        setTestWhileIdle(true);
        setTimeBetweenEvictionRunsMillis(60000);
        setMinEvictableIdleTimeMillis(1800000L);
        setTestOnBorrow(true);
    }
}

針對(duì)FTP連接設(shè)置了一些參數(shù)。

外部只要拿到FtpClientPool對(duì)象就可以獲取FTPClient對(duì)象、返回FTPClien對(duì)象了,
FTPClient的生成銷毀就交給了FtpClientFactory管理。

使用FTP連接對(duì)象池

FTP連接池比方數(shù)據(jù)庫(kù)連接池來(lái)看,使用連接池似乎可以模仿SpringJdbcTemplate,這個(gè)模板封裝了
獲取連接,執(zhí)行數(shù)據(jù)庫(kù)操作,返還連接給連接池的過(guò)程,在這里同樣也適合。這里引入一個(gè)自己實(shí)現(xiàn)的"模板類",

public class FtpTemplate implements FtpOperations {
    @Autowired
    private FtpClientPool ftpClientPool;    
}

繼承自己定義的FTP操作接口,并且注入上一步封裝好的對(duì)象池,當(dāng)然在實(shí)踐過(guò)程中可能做不到像JdbcTemplate
那樣完全的泛型化。
比如為了泛型實(shí)例化,引入InterfaceConfig類我們才能真正實(shí)現(xiàn)FtpTemplate類。

public class FtpTemplate implements FtpOperations {
    ...
    @Override
    public String getFile(InterfaceConfig k, String fileName) throws Exception {
        if (logger.isDebugEnabled()) {
            logger.debug("正在下載" + toFtpInfo(k) + "/" + fileName + "文件");
        }
        final FTPClient client = getFtpClient(getFtpClientPool(), k);
        boolean ret = changeDirectory(client,k);
        
        try {
            if(ret) {
                return performPerFile(client, fileName);
            }
            return null;
        } catch(Exception e) {
            logger.error("下載" + toFtpInfo(k) + "/" + fileName + "文件異常",e);
            throw e;
        } finally {
            //return to object pool
            if(client != null) {
                returnFtpClient(getFtpClientPool(), k, client);
            }
        }
    }
...
}

通過(guò)InterfaceConfig提供對(duì)象池識(shí)別的key獲得我們需要的對(duì)象池里的對(duì)象FTPClient

    private FTPClient getFtpClient(FtpClientPool ftpClientPool, InterfaceConfig k) throws Exception {
        FtpClientConfig config = buildFtpClientConfig(k);
        FTPClient client = null;
        try {
            client = ftpClientPool.borrowObject(config);
        } catch (Exception e) {
            logger.error("獲取FTPClient對(duì)象異常 " + toFtpInfo(k),e);
            throw e;
        }
        return client;
    }
    private FtpClientConfig buildFtpClientConfig(InterfaceConfig k) {
        FtpClientConfig config = new FtpClientConfig();
        config.setHost(k.getFtpUrl());
        config.setPort(Integer.valueOf(k.getFtpPort()));
        config.setUsername(k.getUserName());
        config.setPassword(k.getPwd());
        return config;
    }    

這個(gè)InterfaceConfig是業(yè)務(wù)代碼中的對(duì)象類型,可能是Model類。目前為止我引入了一點(diǎn)點(diǎn)關(guān)于
業(yè)務(wù)的代碼,但還沒(méi)有耦合進(jìn)來(lái)業(yè)務(wù)實(shí)現(xiàn)邏輯。

FTP工具類

其實(shí)FtpTemplate已經(jīng)是一個(gè)適合業(yè)務(wù)邏輯實(shí)現(xiàn)的工具類的,但是它的功能單純一些,為了完成特殊的業(yè)務(wù)功能,
如多線程下載,下載文件業(yè)務(wù)處理成功后才刪除遠(yuǎn)端服務(wù)的文件等,這里再對(duì)FtpTemplate做一次封裝。

public class FtpUtils {
    @Autowired
    private FtpTemplate ftpTemplate;
    private ConcurrentHashMap poolMap = new ConcurrentHashMap<>(); //存儲(chǔ)線程池
    
    public void downloadDirectory(InterfaceConfig config,
             final FtpCallback callback) {
        logger.info("正在下載FTP目錄" + toFtpInfo(config));
        ThreadPoolExecutor workPool = poolMap.get(config.getInterfaceCode());
        if(workPool == null) {
            BlockingQueue workQueue = new LinkedBlockingQueue(100);
            workPool = new ThreadPoolExecutor(MAX_CORE_NUM, MAX_THREAD_NUM, 1, TimeUnit.MINUTES, workQueue);
            poolMap.put(config.getInterfaceCode(), workPool);
        }
        try {
            List fileNames = ftpTemplate.listFiles(config,config.getOrdersCount());
            BlockingQueue fileQueue = new LinkedBlockingQueue(fileNames); //生產(chǎn)者資料
            for(int i = 0; i < config.getThreadNum(); i++) {
                try {
                    workPool.execute(new GetFileConsumer(config, fileQueue, callback));
                } catch (Exception e) {
                    logger.error("提交線程出現(xiàn)異常",e);
                }
            }
        } catch (Exception e) {
            logger.error("FTP操作出現(xiàn)異常"+toFtpInfo(config),e);
        }
        logger.info("下載FTP目錄完成" + toFtpInfo(config));
    }        
}

注入了FtpTemplate,加入了多線程線程池管理,下載方法也需要外部傳入回調(diào)方法。
回調(diào)方法中就可以完成保存下載的FTP文件,刪除遠(yuǎn)端對(duì)應(yīng)的文件等邏輯。即使了多了一層多線程
下載功能的封裝,我們也沒(méi)有把業(yè)務(wù)處理邏輯耦合進(jìn)來(lái)。當(dāng)然,不滿意的地方還是引入了業(yè)務(wù)的Model類。

回調(diào)操作

程序調(diào)用圖

關(guān)于單元測(cè)試

從上往下可以看出來(lái)三處封裝,分別是FtpUtils、FtpTemplateFtpClientPool,我們可以分別
對(duì)他們進(jìn)行單元測(cè)試,

注入FtpClientPool,測(cè)試FTP連接問(wèn)題等

注入FtpTemplate,測(cè)試FTP操作問(wèn)題等

注入FtpUtils,傳入回調(diào)函數(shù),測(cè)試業(yè)務(wù)問(wèn)題

由于JUnit對(duì)多線程單元測(cè)試并沒(méi)有提供支持,所以第3點(diǎn)實(shí)現(xiàn)起來(lái)有困難。

代碼地址

https://github.com/Honwhy/com... 見(jiàn)master分支

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/66241.html

相關(guān)文章

  • 推薦一個(gè)java操作ftp工具

    摘要:寫(xiě)在前面作為經(jīng)常使用電腦整理文件的童鞋,應(yīng)該都使用過(guò)從服務(wù)器上傳下載文件,那么今天就了解下如何通過(guò)程序操作服務(wù)的文件首先你要知道的,路徑,端口,有操作權(quán)限的賬號(hào)和密碼導(dǎo)入包這個(gè)包用來(lái)設(shè)置編碼,經(jīng)過(guò)測(cè)試,不加也可用工具類中主要方法登陸驗(yàn)證 寫(xiě)在前面 作為經(jīng)常使用電腦整理文件的童鞋,應(yīng)該都使用過(guò)從ftp服務(wù)器上傳下載文件,那么今天就了解下如何通過(guò)java程序操作ftp服務(wù)的文件 首先你要知...

    techstay 評(píng)論0 收藏0
  • CodeIgniter 4 建議路線圖

    摘要:核心變化從第一版發(fā)布以來(lái),社區(qū)發(fā)生了巨大變化。這意味著系統(tǒng)必須全部重寫(xiě)。暫時(shí)不會(huì)為一個(gè)即將停止支持的版本發(fā)布新版本。路由路由功能將被更新。改進(jìn)的日志系統(tǒng)日志系統(tǒng)將被改進(jìn),但具體細(xì)節(jié)尚未確定。第一階段第一階段將側(cè)重于抓住框架最重要的部分。 我們綜合考慮了社區(qū)的愿望和意見(jiàn)后,也對(duì)什么樣的未來(lái)對(duì) CI 是最合適的做了一些思考,然后,CI 理事會(huì)對(duì)框架的未來(lái)做出了一些決策。預(yù)告一下,未來(lái)將會(huì)有...

    sean 評(píng)論0 收藏0
  • 工具推薦丨推薦又拍云web版API管理工具,一款輔助使用又拍云的輕量工具

    摘要:沒(méi)想到會(huì)找到其他開(kāi)發(fā)者針對(duì)又拍云開(kāi)發(fā)又拍云管理工具這樣的工具,我個(gè)人覺(jué)得也算是又拍云在接口方面比較開(kāi)放的一個(gè)的案例吧。 今年上半年,我通過(guò)又拍云搭建了一個(gè)獨(dú)立博客,不久之后就遇到了很多實(shí)際問(wèn)題:網(wǎng)上看到圖片想收藏到空間,YouTube上的MV想放到自己的博客,想對(duì)一段音視頻進(jìn)行在線預(yù)覽和編輯……當(dāng)時(shí)我查了下,必須要通過(guò)API接口編寫(xiě)一段程序才能完成(不是程序猿,搭建獨(dú)立博客已經(jīng)要了我半...

    adam1q84 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<