commons-pool和commons-pool2是用来建立对象池的框架,提供了一些将对象池化必须要实现的接口和一些默认动作。对象池化之后可以通过pool的概念去管理其生命周期,例如对象的创建,使用,销毁等。例如我们通常使用的连接池,连接池可以有效管理连接的数量和状态,保证连接资源的情况而且避免并发场景下连接的频繁建立和释放。

我们这里来讲述如何使用commons-pool2来池化对象。我们以池化hadoop连接为例。

1、先解决依赖

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

2、如何使用连接池

我们是在spingboot框架中池化hadoop集群连接,先看一下池化之后的效果。

下面是我们池化之后的hadoop集群客户端。可以看到我们可以通过连接池的方式管理hadoo集群的链接。

1)配置连接池

最大连接数maxTotal

最大空闲连接数maxIdle

最小空闲连接数minIdle

获取连接的最大等待时间maxWait

可以看到传入这些配置的时候我们使用了一个config对象JHadoopPoolConfig,后面我们将说明这个config对象如何实现。

2)管理连接池

我们以三个函数说明了如何去连接池中申请连接,使用连接和释放链接资源。

申请资源pool.getResource()

释放资源pool.returnBrokenResource()和pool.returnResource()

这里要注意的是,一定要在catch和finally中成功释放资源,不然会导致could not get a Resource from the Pool的异常

package com.xiaoju.dqa.jazz.hadoop.client;

import org.apache.hadoop.fs.FileStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;
import java.util.Date;

public class JHadoopClient {
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    private JHadoopPool jHadoopPool;
    private String coreResource;
    private String hdfsResource;
    private int maxTotal;
    private int maxIdle;
    private int minIdle;
    private int maxWaitMillis;

    public String getCoreResource() {
        return coreResource;
    }
    public void setCoreResource(String coreResource) {
        this.coreResource = coreResource;
    }
    public String getHdfsResource() {
        return hdfsResource;
    }
    public void setHdfsResource(String hdfsResource) {
        this.hdfsResource = hdfsResource;
    }
    public int getMaxTotal() {
        return maxTotal;
    }
    public void setMaxTotal(int maxTotal) {
        this.maxTotal = maxTotal;
    }
    public int getMaxIdle() {
        return maxIdle;
    }
    public void setMaxIdle(int maxIdle) {
        this.maxIdle = maxIdle;
    }
    public int getMaxWaitMillis() {
        return maxWaitMillis;
    }
    public void setMaxWaitMillis(int maxWaitMillis) {
        this.maxWaitMillis = maxWaitMillis;
    }
    public int getMinIdle() {
        return minIdle;
    }
    public void setMinIdle(int minIdle) {
        this.minIdle = minIdle;
    }

    public void init() {
        try {
            JHadoopPoolConfig conf = new JHadoopPoolConfig();
            conf.setMaxTotal(maxTotal);
            conf.setMaxIdle(maxIdle);
            conf.setMinIdle(minIdle);
            conf.setMaxWaitMillis(maxWaitMillis);
            jHadoopPool = new JHadoopPool(conf, coreResource, hdfsResource);
            logger.info("[HDFS]初始化JHadoopClient成功");
        } catch (Exception ex) {
            logger.error("[HDFS]初始化JHadoopClient失败", ex);
        }
    }

    public void stop() {
        try {
            jHadoopPool.destroy();
        } catch(Exception e) {
        }
    }

    public boolean exists(String path) throws Exception {
        JHadoop jHadoop = null;
        boolean broken = false;
        try {
            jHadoop = jHadoopPool.getResource();
            return jHadoop.exists(path);
        } catch (Exception e) {
            broken = true;
            jHadoopPool.returnBrokenResource(jHadoop);
            logger.error("[HDFS]判断文件是否存在失败", e);
            throw e;
        } finally {
            if (null != jHadoop && !broken) {
                jHadoopPool.returnResource(jHadoop);
            }
        }
    }

    public String getModificationTime(String path) throws Exception {
        JHadoop jHadoop = null;
        boolean broken = false;
        try {
            jHadoop = jHadoopPool.getResource();
            FileStatus fileStatus = jHadoop.getFileStatus(path);
            long modifyTimestamp = fileStatus.getModificationTime();
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
            Date date = new Date(modifyTimestamp);
            return simpleDateFormat.format(date);
        } catch (Exception e) {
            broken = true;
            jHadoopPool.returnBrokenResource(jHadoop);
            logger.error("[HDFS]获取最近修改时间失败", e);
            throw e;
        } finally {
            if (null != jHadoop && !broken) {
                jHadoopPool.returnResource(jHadoop);
            }
        }
    }

    public long getPathSize(String path) throws Exception {
        JHadoop jHadoop = null;
        boolean broken = false;
        try {
            jHadoop = jHadoopPool.getResource();
            return jHadoop.getContentSummary(path).getLength();
        } catch (Exception e) {
            broken = true;
            jHadoopPool.returnBrokenResource(jHadoop);
            logger.error("[HDFS]获取路径大小失败", e);
            throw e;
        } finally {
            if (null != jHadoop && !broken) {
                jHadoopPool.returnResource(jHadoop);
            }
        }
    }

}

3)注册成bean

通过配置文件传入链接池相应的配置。

package com.xiaoju.dqa.jazz.hadoop.configuration;

import com.xiaoju.dqa.jazz.hadoop.client.JHadoopClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class HadoopConfig {

    @Value("${hadoop.core.resource}")
    private String coreResource;
    @Value("${hadoop.hdfs.resource}")
    private String hdfsResource;
    @Value("${hadoop.pool.maxTotal}")
    private int maxTotal;
    @Value("${hadoop.pool.maxIdle}")
    private int maxIdle;
    @Value("${hadoop.pool.minIdle}")
    private int minIdle;
    @Value("${hadoop.pool.maxWaitMillis}")
    private int maxWaitMillis;

    @Bean(initMethod = "init", destroyMethod = "stop")
    public JHadoopClient jHadoopClient() {
        JHadoopClient jHadoopClient = new JHadoopClient();
        jHadoopClient.setMaxTotal(maxTotal);
        jHadoopClient.setMaxIdle(maxIdle);
        jHadoopClient.setMinIdle(minIdle);
        jHadoopClient.setMaxWaitMillis(maxWaitMillis);
        jHadoopClient.setCoreResource(coreResource);
        jHadoopClient.setHdfsResource(hdfsResource);
        return jHadoopClient;
    }
}

4)config对象如何实现

我们这里要说明一下下面这些参数的含义:

1)setTestWhileConfig - 在空闲时检查有效性, 默认false

2)setMinEvictableIdleTimeMillis - 逐出连接的最小空闲时间

3)setTimeBetweenEvictionRunsMillis - 逐出扫描的时间间隔(毫秒) 如果为负数则不运行逐出线程,默认-1

4)setNumTestsPerEvictionRun - 每次逐出检查时 逐出的最大数目
package com.xiaoju.dqa.jazz.hadoop.client;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

public class JHadoopPoolConfig extends GenericObjectPoolConfig {
    public JHadoopPoolConfig() {
        this.setTestWhileIdle(true);
        this.setMinEvictableIdleTimeMillis(60000L);
        this.setTimeBetweenEvictionRunsMillis(30000L);
        this.setNumTestsPerEvictionRun(-1);
    }
}

3、连接池JHadoopPool

这个类继承了Pool<JHadoop>,用来初始化连接池对象。而JHadoop是Pool要管理的连接对象。

可以看到JHadoopPool在初始化的时候传入了一个JHadoopFactory的实例。这个实例将会以工厂模式来创建实际的JHadoop

JHadoopPool代码

package com.xiaoju.dqa.jazz.hadoop.client;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

public class JHadoopPool extends Pool<JHadoop> {
    public JHadoopPool(GenericObjectPoolConfig poolConfig, String coreResource, String hdfsResource) {
        super(poolConfig, new JHadoopFactory(coreResource, hdfsResource));
    }

    public JHadoopPool(GenericObjectPoolConfig poolConfig) {
        super(poolConfig, new JHadoopFactory());
    }

}

Jhadoop代码

package com.xiaoju.dqa.jazz.hadoop.client;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.ContentSummary;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

public class JHadoop {
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
    private FileSystem fs;
    private String coreResource;
    private String hdfsResource;

    public JHadoop(String coreResource, String hdfsResource) {
        this.coreResource = coreResource;
        this.hdfsResource = hdfsResource;
    }

    public String getCoreResource() {
        return coreResource;
    }
    public void setCoreResource(String coreResource) {
        this.coreResource = coreResource;
    }
    public String getHdfsResource() {
        return hdfsResource;
    }
    public void setHdfsResource(String hdfsResource) {
        this.hdfsResource = hdfsResource;
    }

    public void open() {
        try {
            Configuration conf = new Configuration();
            conf.addResource(coreResource);
            conf.addResource(hdfsResource);
            fs = FileSystem.get(conf);
            logger.info("[JHadoop]创建实例成功");
        } catch (Exception e) {
            logger.error("[JHadoop]创建实例失败", e);
        }
    }

    public void close() {
        try {
            if (null != fs) {
                fs.close();
                logger.info("[JHadoop]关闭实例成功");
            }
        } catch(Exception e) {
            logger.error("[JHadoop]关闭实例失败", e);
        }
    }

    public boolean isConnected() throws IOException {
        fs.exists(new Path("/forTest"));
        return true;
    }

    public boolean exists(String path) throws IOException {
        Path hdfsPath = new Path(path);
        return fs.exists(hdfsPath);
    }

    public FileStatus getFileStatus(String path) throws IOException {
        Path hdfsPath = new Path(path);
        return fs.getFileStatus(hdfsPath);
    }

    public ContentSummary getContentSummary(String path) throws IOException {
        ContentSummary contentSummary = null;
        Path hdfsPath = new Path(path);
        if (fs.exists(hdfsPath)) {
            contentSummary = fs.getContentSummary(hdfsPath);
        }
        return contentSummary;
    }

}

4、连接工厂类JHadoopFactory

JHadoopFactory这个类管理着连接对象的创建,销毁,验证等动作

package com.xiaoju.dqa.jazz.hadoop.client;

import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;

public class JHadoopFactory implements PooledObjectFactory<JHadoop> {
    private final String coreResource;
    private final String hdfsResource;

    public JHadoopFactory() {
        this.coreResource = "core-site.xml";
        this.hdfsResource = "hdfs-site.xml";
    }
    public JHadoopFactory(String coreResource, String hdfsResource) {
        this.coreResource = coreResource;
        this.hdfsResource = hdfsResource;
    }

    @Override
    public PooledObject<JHadoop> makeObject() throws Exception {
        JHadoop jHadoop = new JHadoop(coreResource, hdfsResource);
        jHadoop.open();
        return new DefaultPooledObject<JHadoop>(jHadoop);
    }

    @Override
    public void destroyObject(PooledObject<JHadoop> pooledJHadoop) throws Exception {
        JHadoop jHadoop = pooledJHadoop.getObject();
        jHadoop.close();
    }

    @Override
    public boolean validateObject(PooledObject<JHadoop> pooledJHadoop) {
        JHadoop jHadoop = pooledJHadoop.getObject();
        try {
            return jHadoop.isConnected();
        } catch (Exception e) {
            return false;
        }
    }

    @Override
    public void activateObject(PooledObject<JHadoop> pooledObject) throws Exception {

    }

    @Override
    public void passivateObject(PooledObject<JHadoop> pooledObject) throws Exception {

    }
}

commons-pool与commons-pool2连接池的更多相关文章

  1. 转!数据库连接池概念、种类、配置(DBCP\C3P0\JndI与Tomact配置连接池)

    数据库连接池概念.种类.配置(DBCP\C3P0\JndI与Tomact配置连接池) 一.DBCP 连接:DBCP 连接池是 Apache 软件基金组织下的一个开源连接池实现. 需要的 java 包c ...

  2. 对象池化技术 org.apache.commons.pool

    恰当地使用对象池化技术,可以有效地减少对象生成和初始化时的消耗,提高系统的运行效率.Jakarta Commons Pool组件提供了一整套用于实现对象池化的框架,以及若干种各具特色的对象池实现,可以 ...

  3. DBCP连接池介绍

    DBCP连接池介绍 ----------------------------- 目前 DBCP 有两个版本分别是 1.3 和 1.4. DBCP 1.3 版本需要运行于 JDK 1.4-1.5 ,支持 ...

  4. DBCP连接池原理分析及配置用法

    DBCP连接池介绍 ----------------------------- 目前 DBCP 有两个版本分别是 1.3 和 1.4. DBCP 1.3 版本需要运行于 JDK 1.4-1.5 ,支持 ...

  5. 【转】DBCP连接池原理分析

    ---------------------------- 目前 DBCP 有两个版本分别是 1.3 和 1.4. DBCP 1.3 版本需要运行于 JDK 1.4-1.5 ,支持 JDBC 3. DB ...

  6. Tomcat 连接池详解

    (转) JDBC 连接池 org.apache.tomcat.jdbc.pool 是Apache-Commons DBCP连接池的一种替换或备选方案. 那究竟为何需要一个新的连接池? 原因如下: Co ...

  7. 深入理解Spring Boot数据源与连接池原理

    ​ Create by yster@foxmail.com 2018-8-2 一:开始 在使用Spring Boot数据源之前,我们一般会导入相关依赖.其中数据源核心依赖就是spring‐boot‐s ...

  8. Spring Boot之默认连接池配置策略

    注意:如果我们使用spring-boot-starter-jdbc 或 spring-boot-starter-data-jpa “starters”坐标,Spring Boot将自动配置Hikari ...

  9. java通过代理创建Conncection对象与自定义JDBC连接池

    最近学习了一下代理发现,代理其实一个蛮有用的,主要是用在动态的实现接口中的某一个方法而不去继承这个接口所用的一种技巧,首先是自定义的一个连接池 代码如下 import java.lang.reflec ...

  10. DBCP连接池原理分析(转载)

    DBCP连接池介绍 ----------------------------- 目前 DBCP 有两个版本分别是 1.3 和 1.4. DBCP 1.3 版本需要运行于 JDK 1.4-1.5 ,支持 ...

随机推荐

  1. JTemplates + $.Ajax

    上篇基础使用后: +AJAX 只需要改列名即可 :<script type="text/template" id="foreach">   里的循环 ...

  2. ★电车难题的n个坑爹变种

    哲学家都不会做的电车难题变异 此题会答清华北大 "电车难题(Trolley Problem)"是伦理学领域最为知名的思想实验之一,其内容大致是: 一个疯子把五个无辜的人绑在电车轨道 ...

  3. 团队作业8——第二次项目冲刺(Beta阶段)--5.26 sixth day

    团队作业8--第二次项目冲刺(Beta阶段)--5.26 sixth day Day six: 会议照片 项目进展 Beta冲刺的第四天,以下是今天具体任务安排: 队员 昨天已完成的任务 今日计划完成 ...

  4. 201521123091 《Java程序设计》第1周学习总结

    Java 第一周总结 第一周的作业. 1.本章学习总结 [x] 初识Java语言:Java的历史,三大平台,了解JVM/JRE/JDK [x] Java开发环境的配置 [x] 用记事本编写Java程序 ...

  5. 团队作业8——第二次项目冲刺(Beta阶段)Day1--5.18

    1.展开站立式会议: 会议内容:①团队里的新成员做简单的自我介绍. ②讨论每天的任务分配问题. ③提出一个严格要求:博客一定要及时发布,并及时提交作业,遇到困难可以提出来一起解决. ④就现阶段的项目进 ...

  6. 【Alpha】——Second Scrum Meeting

    一.今日站立式会议照片 二.每个人的工作 成员 昨天已完成的工作 今天计划完成的工作 李永豪 完成登录按钮代码 完成添加功能 郑靖涛 完成登录按钮代码 完成删除功能 杨海亮 完成注册按钮代码 完成查找 ...

  7. 201521123062《Java程序设计》第9周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2. 书面作业 1.常用异常 题目5-1 1.1 截图你的提交结果(出现学号) 1.2 自己以前编写的代码中经常出现 ...

  8. 201521123078 《Java程序设计》第9周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2. 书面作业 1.题目5-1 1.1 截图你的提交结果(出现学号) 1.2 自己以前编写的代码中经常出现什么异常. ...

  9. 子元素设定margin值会影响父元素

    有些情况下,我们设定父元素下的子元素margin值时,父元素会被影响. 这是个常见问题,而且只在标准浏览器下 (FirfFox.Chrome.Opera.Sarfi)产生问题,IE下反而表现良好. 例 ...

  10. Nim函数调用的几种形

    Nim函数调用的几种形式 Nim 转载条件:如果你需要转载本文,你需要做到完整转载本文所有的内容,不得删改文内的作者名字与链接.否则拒绝转载. 关于nim的例行介绍: Nim 是一门静态编译型的系统级 ...