Apache commons-pool对象池妙用

前言

大多时候,咱们获取对象的方法都是直接new一个。可是,对于大对象的构造,或者构造耗时比较久的对象,咱们每次要使用都去new一个是很不科学的。好比数据库的链接对象、redis的链接对象、Http链接请求对象等等。redis

针对这种场景咱们能够建立对象池,这个对象池中维护必定数量的对象,须要的时候就从这个对象池中获取对象,使用完后返还给对象池。这样就避免构造对象所带来的耗时,提高了系统的性能。数据库

为了不造轮子,咱们采用Apache commons-pool对象实现:apache

<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.4.2</version>
</dependency>

实现对象池

ObjectPool的主要方法:多线程

//从对象池中获取对象的方法
    T borrowObject() throws Exception, NoSuchElementException,
            IllegalStateException;
    //将对象返还给对象池
    void returnObject(T obj) throws Exception;
    //让对象失效
    void invalidateObject(T obj) throws Exception;
    //往对象池中新增一个对象
    void addObject() throws Exception, IllegalStateException,
            UnsupportedOperationException;
    //获取当前闲置在对象池中的对象数量,即没有被拿走使用的对象数量
    int getNumIdle();
    //获取已经在使用中的对象数量,即被使用者从对象池中拿走使用的数量
    int getNumActive();
    //清空对象池中闲置的全部对象
    void clear() throws Exception, UnsupportedOperationException;
    //关闭对象池
    void close();

PooledObject,抽象了对象池中对象应该具有的一些属性。注意,这个对象并非咱们真正要存的对象,而是通过一层封装的对象,那么真正存放在对象池的其实都是通过封装过的对象,即PooledObject对象。dom

PooledObjectFactory抽象工厂模型:ide

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;
}

以链接池为例

DbConnection对象:性能

public class DbConnection {

    private Boolean isActive;

    public Boolean getActive() {
        return isActive;
    }

    public void setActive(Boolean active) {
        isActive = active;
    }
}

建立对象工厂DbConnectionFactory:测试

public class DbConnectionFactory implements PooledObjectFactory<DbConnection> {

    @Override
    public PooledObject<DbConnection> makeObject() throws Exception {
        DbConnection dbConnection = new DbConnection();
        //构造一个新的链接对象
        return new DefaultPooledObject<>(dbConnection);
    }

    @Override
    public void destroyObject(PooledObject<DbConnection> p) throws Exception {
        //断开链接
        p.getObject().setActive(false);
    }

    @Override
    public boolean validateObject(PooledObject<DbConnection> p) {
        //判断这个对象是不是保持链接状态
        return p.getObject().getActive();
    }

    @Override
    public void activateObject(PooledObject<DbConnection> p) throws Exception {
        //激活这个对象,让它链接上数据库
        p.getObject().setActive(true);
    }

    @Override
    public void passivateObject(PooledObject<DbConnection> p) throws Exception {
        //不处理
    }
}

测试例子:this

public static void main(String[] args) {
        DbConnectionFactory factory = new DbConnectionFactory();
        //设置对象池的相关参数
        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
        poolConfig.setMaxIdle(20);
        poolConfig.setMaxTotal(100);
        poolConfig.setMinIdle(5);
        //新建一个对象池,传入对象工厂和配置
        GenericObjectPool<DbConnection> objectPool = new GenericObjectPool<>(factory, poolConfig);
        DbConnection dbConnection = null;
        try {
            //从对象池获取对象,若是
            dbConnection = objectPool.borrowObject();
            System.out.println(dbConnection.getActive());
            //使用改对象
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (dbConnection != null) {
                //返还对象
                objectPool.returnObject(dbConnection);
            }
        }
    }

上面的例子中,池化的对象是同样的,若是想池化不同的对象,能够采用键值对的对象GenericKeyedObjectPool 。url

好比新的DbConnection包含多个字段:

public class DbConnection2 {

    private Boolean isActive;
    private String url;

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public Boolean getActive() {
        return isActive;
    }

    public void setActive(Boolean active) {
        isActive = active;
    }
}

实现KeyedPooledObjectFactory 类:

public class DbConnectionKeyFactory implements KeyedPooledObjectFactory<String, DbConnection2> {

    @Override
    public PooledObject<DbConnection2> makeObject(String key) throws Exception {
        DbConnection2 dbConnection2 = new DbConnection2();
        dbConnection2.setUrl(key);
        dbConnection2.setActive(true);
        return new DefaultPooledObject<>(dbConnection2);
    }

    @Override
    public void destroyObject(String key, PooledObject<DbConnection2> p) throws Exception {
        p.getObject().setActive(false);
    }

    @Override
    public boolean validateObject(String key, PooledObject<DbConnection2> p) {
        return p.getObject().getActive();
    }

    @Override
    public void activateObject(String key, PooledObject<DbConnection2> p) throws Exception {
        p.getObject().setActive(true);
    }

    @Override
    public void passivateObject(String key, PooledObject<DbConnection2> p) throws Exception {

    }
}

换一个多线程测试:

public static void run() {
        GenericObjectPoolConfig conf = new GenericObjectPoolConfig();
        conf.setMaxTotal(18);
        conf.setMaxIdle(10);

        StringPoolFactory factory = new StringPoolFactory();
        final GenericObjectPool<String> objectPool = new GenericObjectPool<>(factory, conf);

        for (int i = 0; i < 10; i++) {
            new Thread(new Runnable() {

                @Override
                public void run() {
                    while (true) {
                        try {
                            String result = objectPool.borrowObject();
                            System.out.println("result :" + result);
                            Thread.sleep(100);
                            objectPool.returnObject(result);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }

                }
            }).start();

        }
    }

建立的对象一直被复用:

StringPoolFactory对象:

public class StringPoolFactory implements PooledObjectFactory<String> {

    public StringPoolFactory() {
        System.out.println("init string factory..");
    }

    @Override
    public void activateObject(PooledObject<String> pool) throws Exception {
        // TODO Auto-generated method stub

    }

    @Override
    public void destroyObject(PooledObject<String> pool) throws Exception {
        String str = pool.getObject();
        if (str != null) {
            str = null;
            System.out.println(str + " destroy...");
        }
    }

    @Override
    public PooledObject<String> makeObject() throws Exception {
        String i = UUID.randomUUID().toString();
        System.out.println("make " + i + " success...");
        return new DefaultPooledObject<String>(i);
    }

    @Override
    public void passivateObject(PooledObject<String> pool) throws Exception {
        // TODO Auto-generated method stub

    }

    @Override
    public boolean validateObject(PooledObject<String> pool) {
        // TODO Auto-generated method stub
        return false;
    }

}

使用GenericKeyedObjectPool 对象:

public static void main(String[] args) {
        GenericKeyedObjectPoolConfig genericKeyedObjectPoolConfig = new GenericKeyedObjectPoolConfig();
        genericKeyedObjectPoolConfig.setMaxIdlePerKey(10);
        genericKeyedObjectPoolConfig.setMaxTotalPerKey(100);
        genericKeyedObjectPoolConfig.setMaxTotal(500);
        genericKeyedObjectPoolConfig.setMinIdlePerKey(10);

        DbConnectionKeyFactory dbConnectionKeyFactory = new DbConnectionKeyFactory();
        GenericKeyedObjectPool<String, DbConnection2> genericKeyedObjectPool = new GenericKeyedObjectPool<>
                (dbConnectionKeyFactory, genericKeyedObjectPoolConfig);
        DbConnection2 dbConnection1 = null;
        DbConnection2 dbConnection2 = null;
        try {
            dbConnection1 = genericKeyedObjectPool.borrowObject("192.168.0.1");
            dbConnection2 = genericKeyedObjectPool.borrowObject("192.168.0.2");
            System.out.println(dbConnection1.getUrl());
            System.out.println(dbConnection2.getUrl());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (dbConnection1 != null) {
                genericKeyedObjectPool.returnObject(dbConnection1.getUrl(), dbConnection1);
            }
            if (dbConnection2 != null) {
                genericKeyedObjectPool.returnObject(dbConnection2.getUrl(), dbConnection2);
            }
        }
    }

Config包含的参数:

public static void initConfig(GenericObjectPoolConfig cfg){
		
		  	cfg.setLifo( Boolean.valueOf(SysParamsToolkit.getProperty("lifo", "true"))); 
	        cfg.setMaxTotal( Integer.valueOf(SysParamsToolkit.getProperty("maxActive", "18"))); 
	        cfg.setMaxIdle( Integer.valueOf(SysParamsToolkit.getProperty("maxIdle", "10"))); 
	        cfg.setMaxWaitMillis( Integer.valueOf(SysParamsToolkit.getProperty("maxWait", "150000"))); 
	        cfg.setMinEvictableIdleTimeMillis(Integer.valueOf(SysParamsToolkit.getProperty("minEvictableIdleTimeMillis", "100000"))); 
	        cfg.setMinIdle(Integer.valueOf(SysParamsToolkit.getProperty("minIdle", "0"))); 
	        cfg.setNumTestsPerEvictionRun(Integer.valueOf(SysParamsToolkit.getProperty("numTestsPerEvictionRun", "1"))); 
	        cfg.setTestOnBorrow(Boolean.valueOf(SysParamsToolkit.getProperty("testOnBorrow", "false"))); 
	        cfg.setTestOnReturn(Boolean.valueOf(SysParamsToolkit.getProperty("testOnReturn", "false"))); 
	        cfg.setTestWhileIdle(Boolean.valueOf(SysParamsToolkit.getProperty("testWhileIdle", "false"))); 
	        cfg.setTimeBetweenEvictionRunsMillis(Integer.valueOf(SysParamsToolkit.getProperty("timeBetweenEvictionRunsMillis", "120000"))); 
//	        cfg.whenExhaustedAction = Byte.valueOf("whenExhaustedAction", 1); 
	        cfg.setBlockWhenExhausted(false);
	}
相关文章
相关标签/搜索