体验模式的乐趣(二)—— 连接池与Decorator模式
2005-06-30 22:26 FantasySoft 阅读(1945) 评论(2) 编辑 收藏 举报
在《深入浅出Hibernate》的第一章中,作者讨论了设计一个面向应用的持久层所涉及到的方方面面,其中一个重要的方面就是Connection
Pool(连接池)的使用。以JDBC为例,当你需要对数据表中的数据进行操作的时候,你必须通过Driver去建立与Database的
Connection。由于建立Connection的过程的开销是相当可观的,如果仅仅是在执行了几个简单的SQL语句之后,就把Connection
关掉的话,实在太可惜了。为了能够重用建立起来的Connection,减少系统的开销并提供性能,Conneciton Pool就应运而生了。
通常一个Connection
Pool的实现类会有createConnection,getConnection和releaseConnection三个方法。
createConnection负责创建连接,getConnection负责提供连接,而releaseConnection则负责回收连接。在这
里,我无意对Connection
Pool的具体实现讲述太多(实际是不太懂,呵呵~~~),还是让我们关注一个很关键的问题吧——如何能够保证Connection
Pool中的Connection能够高高兴兴上班去,平平安安回家来呢?也就是如何保证releaseConnection能够顺利回收连接呢?解决这
个问题的关键不在于releaseConnection方法,而是在于Connection本身。我们都知道,一个程序员从Connection
Pool中获得的是一个标准的Connection,也就是说程序员仍然会一不小心调用了close方法把Connection关掉,那么
releaseConection方法就形同虚设,
而Connection的重用也就没有办法实现了。该怎样去解决这个问题呢?我们一定会想到的就是将close方法隐藏起来或者改变close方法的行
为。首先Connection是一个interface,那么我们还是得创建一个新的Connection类型以实现这个interface。
private Connection conn;
private ConnectionPool connPool;
public NewConnection(Connection conn, ConnectionPool connPool) {
this.conn = conn;
this.connPool = connPool;
}
public void close() throws SQLException {
connPool.releaseConnection(conn);
}
//实现interface Connection定义的所有接口
public void commit() throws SQLException {
conn.commit();
}
}
大家会发现,除了close方法之外,其他的方法都是通过调用传入的Connection实例的方法去实现
的。事实上,这里就是使用了Decorator模式。然后修改Connection
Pool的实现类中的getConnection方法,返回NewConnection的一个实例即可,而NewConnection的close方法被
调用的时候,就调用Connection Pool的releaseConneciton方法将连接释放到连接池中。
Decorator模式确实解决了我们的问题,但是NewConnection实现了
Conneciton的接口,因此就得实现Connection定义的所有方法。虽然每个方法的实现都与上面代码中的commit方法一样简单,但是这样
的代码看起来让人觉得冗长而拖沓,毕竟每个方法都是Connection的代理实现。那么有没有简单的实现办法呢?这个时候,强大的反射机制又派上用场
了。
private Connection conn;
private ConnectionPool connPool;
public ConnectionHandler(Conection conn, ConnectionPool connPool) {
this.conn = conn;
this.connPool = connPool;
}
public Connection bind() {
Connection proxyConn = (Connection) Proxy.newProxyInstance(conn.getClass().getClassLoader(), conn.getClass().getInterfaces(), this);
return proxyConn;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object obj = null;
if ("close".equals(method.getName())) {
connPool.releaseConnection(conn);
} else {
obj = method.invoke(conn, args);
}
return obj;
}
}
ConnectionHandler的实现与NewConnection相比是不是简单得多了呢? ConnectionHandler实际上就是Connection的一个代理,所有对于Connection方法的调用都会被invoke方法截获,如 果是close方法被调用,就会作相应的处理——调用releaseConnection方法,而其他方法的调用则不变。这样的实现就显得十分直观了。