由于一般使用的是标准的JDBC Connection,程序员由于编程习惯,可能会习惯性的调用close方法关闭连接。这样一来连接无法得到重用,数据库连接池机制形同虚设。解决这个问题的好的办法是使用Dynamic Proxy模式。
通过实现一个绑定到Connection对象的InvocationHandler接口实现,我们可以在Connection.close方法被调用时将其截获,并以我们自己实现的close方法将其替代,使连接返回到连接池等待下次重用,而不是直接关闭。
(这段话来自《深入浅出Hibernate》)
1 动态代理绑定类------将动态代理绑定到连接,截取close方法,替换成连接池的回收连接方法(将连接重新放回池中)
package cn.kai.datasource_proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
public class ConnectionHandler implements InvocationHandler {
private Connection realConnection;
private DBConnectionPool pool;
public ConnectionHandler(DBConnectionPool pool) {
this.pool = pool;
}
/**
* 将动态代理绑定到指定Connection
* @param conn
* @return 绑定代理后的Connection
*/
public Connection bind(Connection conn) {
this.realConnection = conn;
Connection proxyConn = (Connection)Proxy.newProxyInstance(
conn.getClass().getClassLoader(),
conn.getClass().getInterfaces(),
this);
return proxyConn;
}
/**
* 方法调用拦截器
* 判断当前调用的方法是否是close方法
* 如是,调用pool.releaseConnectin方法作为标准close方法的替代
* */
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object obj = null;
if("close".equals(method.getName())) {
pool.releaseConnection(realConnection);
System.out.println("not really closed");
}else {
obj = method.invoke(realConnection, args);
}
return obj;
}
}
2简单连接池代码
package cn.kai.datasource_proxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;
/**
* 使用了动态代理的简单连接池
* @author zhangkai
*
*/
public class DBConnectionPool {
private String url = "jdbc:mysql://localhost:3306/airline_jdbc";
private String username = "root";
private String password = "root";
/* 使用LinkedList作为连接的容器 */
private LinkedList
/** 初始化连接数 */
private static int init_connection_count = 5;
/** 最大连接数 */
private static int max_connection_count = 10;
/** 当前连接数 */
int current_connection_count = 0;
public DBConnectionPool() {
for(int i = 0; i < init_connection_count; i++) {
try {
this.pool.addLast(this.createConnection());
this.current_connection_count++;
} catch (Exception e) {
e.printStackTrace();
throw new ExceptionInInitializerError(e);
}
}
}
public Connection getConnection() throws Exception {
/*防止并发访问时资源冲突*/
synchronized(pool) {
if(pool.size() > 0) {
return pool.removeFirst();
}
if(this.current_connection_count < max_connection_count) {
this.current_connection_count++;
return this.createConnection();
}
throw new Exception("连接已用尽");
}
}
/**释放连接*/
public void releaseConnection(Connection conn) {
if(pool.size() < max_connection_count) {
this.pool.addLast(conn);
}else {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**真正创建连接的方法*/
private Connection createConnection() throws Exception {
//在JDBC工具类中加载驱动
Connection conn = DriverManager.getConnection(url,username,password);
ConnectionHandler proxy = new ConnectionHandler(this);
//返回使用了动态代理绑定的连接,在以后关闭该连接时,实际上被放回了连接池
return proxy.bind(conn);
}
}