利用apache-commons-pool2池化管理重量级对象
SpringBoot集成apache-commons-pool2池化管理重量级对象
一、连接池概述
频繁地创建和销毁重量级对象,会极大的降低系统的性能。而对象池会在初始化的时候会创建一定数量的对象,每次访问只需从对象池中借用对象,用完后再归还给对象池,并不直接销毁,这样可以保证程序重复使用同一批对象,而不需要每次都创建和销毁对象,从而提高系统性能。
二、使用apache-commons-pool2
1.入commons-pool2依赖
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.6.2</version>
</dependency>
pool2的关键对象
PooledObject //池化对象
PooledObjectFactory //对象工厂
ObjectPool //对象池
2.定义需要池化的重量级对象
/**
* 需要池化的【重量级对象】
*
* @author lz
* @date 2019/7/30
*/
public class TestObject {
private String name;
private boolean isActive;
public TestObject() {
}
public TestObject(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isActive() {
return isActive;
}
public void setActive(boolean active) {
isActive = active;
}
public void destroy(){
}
}
3.定义池化对象工厂
在commons-pool2中有两类工厂:PooledObjectFactory
和KeyedPooledObjectFactory
我们使用前者。
public interface PooledObjectFactory<T> {
//创建对象
PooledObject<T> makeObject();
//激活对象
void activateObject(PooledObject<T> obj);
//钝化对象
void passivateObject(PooledObject<T> obj);
//验证对象
boolean validateObject(PooledObject<T> obj);
//销毁对象
void destroyObject(PooledObject<T> obj);
}
创建TestObjectFactory只需要继承BasePooledObjectFactory这个抽象类,而它则实现了PooledObjectFactory,也可以直接实现PooledObjectFactory接口;
我们这里直接实现PooledObjectFactory接口:
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
/**
* TestObject 工厂类
*
* @author lz
* @date 2019/7/30
*/
public class TestObjectFactory implements PooledObjectFactory<TestObject> {
/**
* /构造一个封装对象
*
* @return
* @throws Exception
*/
@Override
public PooledObject<TestObject> makeObject() throws Exception {
return new DefaultPooledObject<>(new TestObject());
}
/**
* 销毁对象
*
* @param p
* @throws Exception
*/
@Override
public void destroyObject(PooledObject<TestObject> p) throws Exception {
p.getObject().destroy();
}
/**
* 验证对象是否可用
*
* @param p
* @return
*/
@Override
public boolean validateObject(PooledObject<TestObject> p) {
return p.getObject().isActive();
}
/**
* 激活一个对象,使其可用用
*
* @param p
* @throws Exception
*/
@Override
public void activateObject(PooledObject<TestObject> p) throws Exception {
p.getObject().setActive(true);
}
/**
* 钝化一个对象,也可以理解为反初始化
*
* @param p
* @throws Exception
*/
@Override
public void passivateObject(PooledObject<TestObject> p) throws Exception {
}
}
4.创建一个对象池
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.AbandonedConfig;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
/**
* 自定义对象池
*
* @author lz
* @date 2019/7/30
*/
public class TestObjectPool extends GenericObjectPool<TestObject> {
public TestObjectPool(PooledObjectFactory<TestObject> factory) {
super(factory);
}
public TestObjectPool(PooledObjectFactory<TestObject> factory, GenericObjectPoolConfig<TestObject> config) {
super(factory, config);
}
public TestObjectPool(PooledObjectFactory<TestObject> factory, GenericObjectPoolConfig<TestObject> config, AbandonedConfig abandonedConfig) {
super(factory, config, abandonedConfig);
}
}
5.集成Spring
- 创建对象池配置类
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 对象池配置
*
* @author lz
* @date 2019/7/30
*/
@ConfigurationProperties(prefix = PoolProperties.PROJECT_PREFIX)
public class PoolProperties {
public static final String PROJECT_PREFIX = "project.object";
/**
* 最大空闲
*/
private int maxIdle = 5;
/**
* 最大总数
*/
private int maxTotal = 20;
/**
* 最小空闲
*/
private int minIdle = 2;
/**
* 初始化连接数
*/
private int initialSize = 3;
public int getMaxIdle() {
return maxIdle;
}
public void setMaxIdle(int maxIdle) {
this.maxIdle = maxIdle;
}
public int getMaxTotal() {
return maxTotal;
}
public void setMaxTotal(int maxTotal) {
this.maxTotal = maxTotal;
}
public int getMinIdle() {
return minIdle;
}
public void setMinIdle(int minIdle) {
this.minIdle = minIdle;
}
public int getInitialSize() {
return initialSize;
}
public void setInitialSize(int initialSize) {
this.initialSize = initialSize;
}
}
- 创建自动配置类
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PreDestroy;
/**
* 对象池自动装配
*
* @author lz
* @date 2019/7/30
*/
@Configuration
@EnableConfigurationProperties(PoolProperties.class)
public class PoolAutoConfiguration {
private TestObjectPool pool;
private final PoolProperties poolProperties;
@Autowired
public PoolAutoConfiguration(PoolProperties poolProperties) {
this.poolProperties = poolProperties;
}
@Bean
@ConditionalOnClass({TestObjectFactory.class})
protected TestObjectPool faceSDKPool() {
TestObjectFactory faceSDKFactory = new TestObjectFactory();
//设置对象池的相关参数
GenericObjectPoolConfig<TestObject> poolConfig = new GenericObjectPoolConfig<>();
poolConfig.setMaxIdle(poolProperties.getMaxIdle());
poolConfig.setMaxTotal(poolProperties.getMaxTotal());
poolConfig.setMinIdle(poolProperties.getMinIdle());
poolConfig.setBlockWhenExhausted(true);
poolConfig.setTestOnBorrow(true);
poolConfig.setTestOnReturn(true);
poolConfig.setTestWhileIdle(true);
poolConfig.setTimeBetweenEvictionRunsMillis(1000 * 60 * 30);
//一定要关闭jmx,不然springboot启动会报已经注册了某个jmx的错误
poolConfig.setJmxEnabled(false);
//新建一个对象池,传入对象工厂和配置
pool = new TestObjectPool(faceSDKFactory, poolConfig);
initPool(poolProperties.getInitialSize(), poolProperties.getMaxIdle());
return pool;
}
/**
* 预先加载testObject对象到对象池中
*
* @param initialSize 初始化连接数
* @param maxIdle 最大空闲连接数
*/
private void initPool(int initialSize, int maxIdle) {
if (initialSize <= 0) {
return;
}
int size = Math.min(initialSize, maxIdle);
for (int i = 0; i < size; i++) {
try {
pool.addObject();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@PreDestroy
public void destroy() {
if (pool != null) {
pool.close();
}
}
}
1.maxActive: 链接池中最大连接数,默认为8.
2.maxIdle: 链接池中最大空闲的连接数,默认为8.
3.minIdle: 连接池中最少空闲的连接数,默认为0.
4.maxWait: 当连接池资源耗尽时,调用者最大阻塞的时间,超时将跑出异常。单位,毫秒数;默认为-1.表示永不超时.
5.minEvictableIdleTimeMillis: 连接空闲的最小时间,达到此值后空闲连接将可能会被移除。负值(-1)表示不移除。
6.softMinEvictableIdleTimeMillis: 连接空闲的最小时间,达到此值后空闲链接将会被移除,且保留“minIdle”个空闲连接数。默认为-1.
7.numTestsPerEvictionRun: 对于“空闲链接”检测线程而言,每次检测的链接资源的个数。默认为3.
8.testOnBorrow: 向调用者输出“链接”资源时,是否检测是有有效,如果无效则从连接池中移除,并尝试获取继续获取。默认为false。建议保持默认值.
9.testOnReturn: 向连接池“归还”链接时,是否检测“链接”对象的有效性。默认为false。建议保持默认值.
10.testWhileIdle: 向调用者输出“链接”对象时,是否检测它的空闲超时;默认为false。如果“链接”空闲超时,将会被移除。建议保持默认值.
11.timeBetweenEvictionRunsMillis: “空闲链接”检测线程,检测的周期,毫秒数。如果为负值,表示不运行“检测线程”。默认为-1.
12.whenExhaustedAction: 当“连接池”中active数量达到阀值时,即“链接”资源耗尽时,连接池需要采取的手段:
0:抛出异常。
1:阻塞直到有可用链接资源。
2:强制创建新的链接资源
默认为1。
这些属性均可以在org.apache.commons.pool.impl.GenericObjectPool.Config中进行设定。
- 使用对象池来管理对象。
@Autowired
private TestObjectPool testObjectPool;
public void test() {
TestObject testObject = null;
try {
testObject = testObjectPool.borrowObject();
//省略业务代码...
} catch (Exception e) {
e.printStackTrace();
} finally {
if (testObject != null) {
//最终归还对象到对象池
testObjectPool.returnObject(testObject);
}
}
}