我不会从池中返回“真正的”连接对象,而是返回一个包装器,它为池提供了连接生命周期的控制,而不是客户端。
假设您有一个非常简单的连接,您可以从中读取值:int
interface Connection {
int read(); // reads an int from the connection
void close(); // closes the connection
}
从流读取的实现可能如下所示(忽略异常、EOF 处理等):
class StreamConnection implements Connection {
private final InputStream input;
int read(){ return input.read(); }
void close(){ input.close(); }
}
此外,假设您有一个如下所示的池(再次忽略异常,并发等):StreamConnection
class StreamConnectionPool {
List<StreamConnection> freeConnections = openSomeConnectionsSomehow();
StreamConnection borrowConnection(){
if (freeConnections.isEmpty()) throw new IllegalStateException("No free connections");
return freeConnections.remove(0);
}
void returnConnection(StreamConnection conn){
freeConnections.add(conn);
}
}
这里的基本思想是可以的,但是我们无法确定连接是否返回,并且我们无法确定它们是否已关闭然后返回,或者您没有返回完全来自另一个源的连接。
解决方案(当然)是另一层间接层:创建一个池,该池返回一个包装器,该包装器在调用时不关闭底层连接,而是将其返回到池中:Connection
close()
class ConnectionPool {
private final StreamConnectionPool streamPool = ...;
Connection getConnection() {
final StreamConnection realConnection = streamPool.borrowConnection();
return new Connection(){
private boolean closed = false;
int read () {
if (closed) throw new IllegalStateException("Connection closed");
return realConnection.read();
}
void close() {
if (!closed) {
closed = true;
streamPool.returnConnection(realConnection);
}
}
protected void finalize() throws Throwable {
try {
close();
} finally {
super.finalize();
}
}
};
}
}
这将是客户端代码唯一能看到的东西。假设它是 的唯一所有者,这种方法有几个优点:ConnectionPool
StreamConnectionPool
降低了复杂性,对客户端代码的影响最小 - 自行打开连接和使用池之间的唯一区别是使用工厂来获取 s(如果您使用的是依赖关系注入,则可能已经这样做了)。最重要的是,您始终以相同的方式清理资源,即通过调用 .就像你不在乎什么一样,只要它给你你需要的数据,你就不在乎什么,只要它释放了你声称的资源。您不必考虑此连接是否来自池。Connection
close()
read
close()
防止恶意/错误使用 - 客户端只能返回从池中检索到的资源;他们无法关闭底层连接;他们不能使用他们已经返回的连接...等。
资源的“保证”返回 - 由于我们的实现,即使所有对借入的引用都丢失了,它仍然会返回到池中(或者至少有机会被返回)。当然,这种连接将保持比必要的时间更长 - 可能是无限期的,因为最终确定不能保证运行 - 但这是一个小小的改进。finalize
Connection