激励示例:我有一个 HTTP 客户端,其唯一目的是生成单个
InputStream
。一旦 InputStream
关闭,HTTP 客户端也应该关闭。有没有办法将 HTTP 客户端的 close()
方法订阅到流的方法?
真正的问题是通用地这样做。我可以创建
InputStream
的子类覆盖 close()
并添加 httpClient.close()
,但也许明天我会面临同样的问题,但它不是 Http 客户端,而是文件句柄,或者我需要处置多个资源 B,当 A 关闭时 C、D,依此类推。能够将可关闭资源“订阅”到另一个资源将是理想的选择,但 API 似乎不支持这一点。
我认为你可以使用侦听器或观察者模式。这种模式允许一个资源(例如,InputStream)在关闭时通知订阅的资源,从而有效地创建订阅机制。
例如
public class SubscribableCloseable implements Closeable {
private final Closeable mainResource;
private final List<Closeable> subscribers = new ArrayList<>();
public SubscribableCloseable(Closeable mainResource) {
this.mainResource = mainResource;
}
public void subscribe(Closeable resource) {
if (resource != null) {
subscribers.add(resource);
}
}
@Override
public void close() throws IOException {
IOException exception = null;
try {
// Close the main resource first
mainResource.close();
} catch (IOException e) {
exception = e; // Capture any exception from the main resource close
} finally {
// Close all subscribed resources
for (Closeable subscriber : subscribers) {
try {
subscriber.close();
} catch (IOException e) {
if (exception == null) {
exception = e; // Capture the first exception encountered
} else {
e.printStackTrace(); // Log subsequent exceptions
}
}
}
}
// If any exception occurred during closing, throw the first one encountered
if (exception != null) {
throw exception;
}
}
}
现在您可以将多个可关闭资源订阅到一个主可关闭资源,例如 InputStream。
public class HttpClientExample {
public static void main(String[] args) throws IOException {
URL url = new URL("http://example.com");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
InputStream inputStream = connection.getInputStream();
SubscribableCloseable subscribableStream = new SubscribableCloseable(inputStream);
// Subscribe the HttpURLConnection to the InputStream's close event
subscribableStream.subscribe(() -> connection.disconnect());
// Use the InputStream as needed
// ... (read from the stream, process data, etc.)
// Close the SubscribableCloseable, which triggers all subscribed closeables
subscribableStream.close();
}
}