工厂方法模式最终也是符合“开放-封闭”原则的,可以通过添加新的 Factory 接口实现和 Product 接口实现来扩展整个体系的功能 。
MyBatis 的数据源模块也是用到了工厂方法模式,如果需要扩展新的数据源实现时,只需要添加对应的 Factory 实现类,新的数据源就可以被 MyBatis 使用。
DataSourceFactory接口及其实现
DataSource及实现
全局配置文件的mybatis-config.xml
解析全局配置文件的mybatis-config.xml
看一下,数据库连接池的几个关键方法
1. 获取连接
2.创建连接,通过class PooledConnection implements InvocationHandler动态创建
主要是拦截Close方法
3.PooledDataSource的核销方法 push和pop
private PooledConnection popConnection(String username, String password) throws SQLException {
while (conn == null) {
synchronized (state) { // 加锁同步
// 步骤1:检测空闲连接集合
if (!state.idleConnections.isEmpty()) {
// 获取空闲连接
conn = state.idleConnections.remove(0);
} else { // 没有空闲连接
// 步骤2:活跃连接数没有到上限值,则创建新连接
if (state.activeConnections.size() < poolMaximumActiveConnections) {
// 创建新数据库连接,并封装成PooledConnection对象
conn = new PooledConnection(dataSource.getConnection(), this);
} else {// 活跃连接数已到上限值,则无法创建新连接
// 步骤3:检测超时连接
// 获取最早的活跃连接
PooledConnection oldestActiveConnection = state.activeConnections.get(0);
long longestCheckoutTime = oldestActiveConnection.getCheckoutTime();
// 检测该连接是否超时
if (longestCheckoutTime > poolMaximumCheckoutTime) {
// 对超时连接的信息进行统计
state.claimedOverdueConnectionCount++;
state.accumulatedCheckoutTimeOfOverdueConnections += longestCheckoutTime;
state.accumulatedCheckoutTime += longestCheckoutTime;
// 将超时连接移出activeConnections集合
state.activeConnections.remove(oldestActiveConnection);
// 如果超时连接上有未提交的事务,则自动回滚
if (!oldestActiveConnection.getRealConnection().getAutoCommit()) {
try {
oldestActiveConnection.getRealConnection().rollback();
} catch (SQLException e) {
}
}
// 创建新PooledConnection对象,但是真正的数据库连接
conn = new PooledConnection(oldestActiveConnection.getRealConnection(), this);
conn.setCreatedTimestamp(oldestActiveConnection.getCreatedTimestamp());
conn.setLastUsedTimestamp(oldestActiveConnection.getLastUsedTimestamp());
// 将超时PooledConnection设置为无效
oldestActiveConnection.invalidate();
} else {
// 步骤4:无空闲连接、无法创建新连接且无超时连接,则只能阻塞等待
if (!countedWait) { // 统计阻塞等待次数
state.hadToWaitCount++;
countedWait = true;
}
long wt = System.currentTimeMillis();
state.wait(poolTimeToWait);// 阻塞等待
// 统计累积的等待时间
state.accumulatedWaitTime += System.currentTimeMillis() - wt;
}
}
}
if (conn != null) { // 对连接进行统计
if (conn.isValid()) { // 检测PooledConnection是否有效
// 配置PooledConnection的相关属性,设置connectionTypeCode、checkoutTimestamp、lastUsedTimestamp字段的值
conn.setConnectionTypeCode(assembleConnectionTypeCode(dataSource.getUrl(), username, password));
conn.setCheckoutTimestamp(System.currentTimeMillis());
conn.setLastUsedTimestamp(System.currentTimeMillis());
state.activeConnections.add(conn); // 添加到活跃连接集合
state.requestCount++;
state.accumulatedRequestTime += System.currentTimeMillis() - t;
} else {
... ...// 统计失败的情况
}
}
}
}
return conn;
}
protected void pushConnection(PooledConnection conn) throws SQLException {
synchronized (state) {
state.activeConnections.remove(conn); // 步骤1:从活跃连接集合中删除该连接
if (conn.isValid()) {// 步骤2:检测该 PooledConnection 对象是否可用
// 步骤3:检测当前PooledDataSource连接池中的空闲连接是否已经达到上限值
if (state.idleConnections.size() < poolMaximumIdleConnections && conn.getConnectionTypeCode() == expectedConnectionTypeCode) {
// 累计增加accumulatedCheckoutTime
state.accumulatedCheckoutTime += conn.getCheckoutTime();
if (!conn.getRealConnection().getAutoCommit()) {
// 回滚未提交的事务
conn.getRealConnection().rollback();
}
// 步骤4:将底层连接重新封装成PooledConnection对象,
// 并添加到空闲连接集合(也就是前面提到的 idleConnections 集合)
PooledConnection newConn = new PooledConnection(conn.getRealConnection(), this);
state.idleConnections.add(newConn);
// 设置新PooledConnection对象的创建时间戳和最后使用时间戳
newConn.setCreatedTimestamp(conn.getCreatedTimestamp());
newConn.setLastUsedTimestamp(conn.getLastUsedTimestamp());
conn.invalidate(); // 丢弃旧PooledConnection对象
// 唤醒所有阻塞等待空闲连接的线程
state.notifyAll();
} else {
// 当前PooledDataSource连接池中的空闲连接已经达到上限值
// 当前数据库连接无法放回到池中
// 累计增加accumulatedCheckoutTime
state.accumulatedCheckoutTime += conn.getCheckoutTime();
if (!conn.getRealConnection().getAutoCommit()) {
// 回滚未提交的事务
conn.getRealConnection().rollback();
}
// 关闭真正的数据库连接
conn.getRealConnection().close();
// 将PooledConnection对象设置为无效
conn.invalidate();
}
} else {
// 统计无效PooledConnection对象个数
state.badConnectionCount++;
}
}
}