我正在尝试模块化我的代码,但它涉及传递实现AutoCloseable的对象。假设我有两个公共方法foo1和foo2:
public class MyClass {
public void foo1() {
// Connection implements AutoCloseable
try (Connection conn = createConnection()) {
foo2(conn);
// is the connection closed or the behavior unpredictable?
conn.doSomethingElse();
}
}
public void foo2(Connection conn) {
try (conn) {
// do something with the Connection
}
}
}
我想从foo1调用foo2,但也允许其他类分别使用foo2。
public class OtherClass {
public void doSomething() {
MyClass myClass = new MyClass();
myClass.foo2(createConnection());
}
}
在调用foo2之后,这会导致foo1()中的连接被关闭吗?或者我应该将try-with-resources放在调用方法中(例如OtherClass中的doSomething())?
答案 0 :(得分:2)
您的foo1
方法会在foo2
使用后关闭连接。 foo2
无需关闭连接,也不应该。你正在使它产生意想不到的副作用。例如。当您在conn.doSomethingElse()
内拨打foo1
时,您会发现它无法正常工作,因为通过调用foo2
已关闭连接。它违反了principle of least astonishment,因为方法名称并未显示此副作用。
如果你打电话给它foo2AndCloseTheConnection
,那么你会明确它的作用,但我建议遵循经验法则创建closeable的方法应该是唯一关闭它的方法。如果你始终如一地遵循这一点,那么你永远不需要查看一个函数来查看你所打开的东西是否被该函数关闭。你只需要明确地自己关闭它。
如果您希望从其他方法调用foo2
,则需要使这些方法关闭连接:
public void doSomething() {
MyClass myClass = new MyClass();
try (Connection connection = createConnection()) {
myClass.foo2(connection);
}
}
答案 1 :(得分:1)
是的,foo2会关闭连接,因此当控制权返回foo1时它将无效。没有什么不可预测的。
通过创建它们的相同代码关闭事物是一个很好的规则。但是能够嵌套这些东西并让它们共享相同的连接和事务将是一件好事。一种解决方案是让每个这些数据访问方法接收连接作为参数,并具有获得连接的外层并确保它被关闭。
你基本上试图一次重塑一下Spring。 Spring使您能够拥有可以使用相同连接的服务,并允许您控制事务在它们之间传播的方式和方式。这是通过使用AOP来封装带有around的对象来完成的,这些通知从线程局部数据结构获取线程的当前连接。更容易使用弹簧(或任何容器)。