Java对象池与连接池
对象池工厂:利用对象池中封闭的创建、获取、归还和销毁操作对象。
- 当需要拿一个池对象的时候, 就从容器中取出一个。
- 如果容器中没有的话, 而且又没有达到容器的最大限制, 那么就调用池对象工厂, 新建一个池对象, 并调用工厂的激活方法, 对创建的对象进行激活, 验证等一系列操作;
- 如果已经达到池容器的最大值, 而对象池中又经没有空闲的对象, 那么将会继续等待, 直到有新的空闲的对象被丢进来, 当然这个等待也是有限度的, 如果超出了这个限度, 对象池就会抛出异常.
当将用完的池对象归还到对象池中的时候, 对象池会调用池对象工厂对该池对象进行验证:
- 如果验证不通过则被认为是有问题的对象, 将会被销毁;
- 如果容器已经满了, 这个归还池对象将变的"无家可归", 也会被销毁,;
- 如果不属于上面两种情况, 对象池就会调用工厂对象将其钝化并放入容器中.
在整个过程中, 激活, 检查, 钝化处理都不是必须的, 因此我们在实现PoolableObjectFactory接口的时候, 一般不作处理, 给空实现即可, 所以诞生了BasePoolableObjectFactory.
对象池共分5种、2类:
- GenericObjectPool :CursorableLinkedList容器
- GenericKeyedObjectPool :CursorableLinkedList容器
- SoftReferenceObjectPool :ArrayList容器--一次性创建所有池化对象, 并对容器中的对象进行了软引用(SoftReference)处理, 从而保证在内存充足的时候池对象不会轻易被jvm垃圾回收, 从而具有很强的缓存能力.
- StackObjectPool : Stack容器
- StackKeyedObjectPoo : Stack容器
四种池对象的区别主要体现在内部的容器的区别:
Stack遵循"后进先出"的原则并能保证线程安全;
CursorableLinkedList是一个内部用游标(cursor)来定位当前元素的双向链表, 是非线程安全的, 但是能满足对容器的并发修改.ArrayList是非线程安全的, 便利方便的容器.
一、不带Key的对象池
二、带Key的对象池
普通的对象池通过makeObject()方法创建的对象基本上都是一模一样的, 因为没法传递参数来对池对象进行定制
使用对象池步骤:
创建一个池对象工厂
- 将工厂注入到对象池中
- 取池对象时:borrowOjbect
- 归还池对象:returnObject
- 销毁池对象: clear()
- 连池对象工厂一起销毁:close()
borrowOjbect:
returnObject:
invalidateObject:
源代码:
/**
* 创建连接
*
*/
public class ConnectionUtils {
// 一些common-dbcp内部定义的protocol
private static final String POOL_DRIVER_KEY = "jdbc:apache:commons:dbcp:";
private static final String POLLING_DRIVER = "org.apache.commons.dbcp.PoolingDriver";
/**
* 取得池化驱动器
*
* @return
* @throws ClassNotFoundException
* @throws SQLException
*/
private static PoolingDriver getPoolDriver() throws ClassNotFoundException,
SQLException {
Class.forName(POLLING_DRIVER);
return (PoolingDriver) DriverManager.getDriver(POOL_DRIVER_KEY);
}
/**
* 销毁所有连接
*
* @throws Exception
*/
public static void destory() throws Exception {
PoolingDriver driver = getPoolDriver();
String[] names = driver.getPoolNames();
for (String name : names) {
driver.getConnectionPool(name).close();
}
}
/**
* 从连接池中获取数据库连接
*/
public static Connection getConnection(TableMetaData table)
throws Exception {
String key = table.getConnectionKey();
PoolingDriver driver = getPoolDriver();
ObjectPool pool = null;
// 这里找不到连接池会抛异常, 需要catch一下
try {
pool = driver.getConnectionPool(key);
} catch (Exception e) {
}
if (pool == null) {
// 根据数据库类型构建连接工厂
ConnectionFactory connectionFactory = null;
if (table.getDbAddr() != null
&& TableMetaData.DB_TYPE_MYSQL == table.getDbType()) {
Class.forName(TableMetaData.MYSQL_DRIVER);
connectionFactory = new DriverManagerConnectionFactory(table
.getDBUrl(), null);
} else {
Class.forName(TableMetaData.ORACLE_DRIVER);
connectionFactory = new DriverManagerConnectionFactory(table
.getDBUrl(), table.getDbuser(), table.getDbpass());
}
// 构造连接池
ObjectPool connectionPool = new GenericObjectPool(null);
new PoolableConnectionFactory(connectionFactory, connectionPool,
null, null, false, true);
// 将连接池注册到driver中
driver.registerPool(key, connectionPool);
}
// 从连接池中拿一个连接
return DriverManager.getConnection(POOL_DRIVER_KEY + key);
}
}