我已经看到这种模式现在在几个不同的地方使用,但我不确定它到底是什么或为什么需要它。鉴于我已经在优质项目中看到它,我确信它很有用,但我想理解它,而不是盲目地遵循它。我在Servlet过滤器和Struts2拦截器中特别看到了这种模式(在概念上与过滤器非常相似)。
以下是Google Guice(Servlet)3.0的一个示例:
Context previous = localContext.get();
try {
localContext.set(new Context((HttpServletRequest) servletRequest,
(HttpServletResponse) servletResponse));
//dispatch across the servlet pipeline, ensuring web.xml's filterchain is honored
filterPipeline.dispatch(servletRequest, servletResponse, filterChain);
} finally {
localContext.set(previous);
}
恢复finally块中的值有什么需要或好处?
答案 0 :(得分:5)
它基本上只是将更改范围限定为try
块。无论块是否成功执行,您都知道,一旦您离开它,您就已将值恢复为进入时的值。
答案 1 :(得分:4)
这是一种非常有用的模式,它有效地模拟了Java中的非词法作用域。考虑本地上下文本质上是一个全局变量,或者更常见的是一个线程局部变量。您可以将全局修改为设置值(因为您不希望传递给称为HTTP请求和响应的每个方法),这些方法可以在调用堆栈深处的方法中稍后检索。如果你想嵌套这些修改,一个例外可能会让你失控 - 因此这个构造。无论发生什么(没有VM崩溃或OS强制进程终止),最终块将在堆栈展开时执行,其工作是撤消对全局变量的修改,因为功能的嵌套不再需要的。
另见Thread #setContextClassLoader()。
答案 2 :(得分:0)
我将尝试给出另一个例子,我们发现这种模式很有用。它特意说:“在使用try / catch块完成后,将(通常)全局资源恢复到可预测状态”。
示例:我们正在使用数据库连接池=>我们知道创建新连接是昂贵的,我们希望重用有限的连接池。所以一些servlet类中的try块以Connection开头,创建它的Statement和ResultSet,将结果写入ObjectOutputStream等。这些可能导致SQLException(有人在db表中删除了无用的列,而sql现在失败了)和/或我们在catch块中捕获IOException(客户端http连接断开,而servlet仍然写入它)。现在,无论是否抛出异常,我们都希望关闭db Connection,以便其他线程可以使用它。这个结束是在finally块中完成的。
希望有所帮助, - M.S。