【发布时间】:2014-03-22 04:18:53
【问题描述】:
以下是问题的要求:
- 在 Tomcat 7 中运行的 java Web 应用程序
- 初始化代码需要与外部数据库对话
- 外部数据库在应用程序启动期间可能不可用
- 应用程序启动不能失败,否则tomcat会将应用程序标记为未运行并且不会向应用程序发送任何请求。相反,应用程序应该启动接受请求,如果它发现应用程序特定的初始化未完成,它应该尝试在请求处理期间完成它。
我正在尝试使用下面的 servlet 过滤器来解决问题。我有以下问题。
- 这个 Servlet 过滤线程安全吗,它会只执行一次初始化代码吗?
- 有没有办法在不使用 servlet 过滤器的情况下解决这个问题?
- 有没有更好的方法来解决这个问题?
package com.exmaple;
@WebFilter("/*")
public class InitFilter implements Filter
{
private volatile boolean initialized = false;
public void destroy() {
System.out.println("InitFilter.destroy()");
}
// is this method thread safe and will only execute the init code once
// and will cause all requests to wait until initialization code is executed
// thread code
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("InitFilter.doFilter()");
if (initialized == false) {
synchronized (this) {
// do expensive initialization work here
initialized = true;
}
}
chain.doFilter(request, response);
}
public void init(FilterConfig fConfig) throws ServletException {
System.out.println("InitFilter.init()");
}
}
【问题讨论】:
-
您可以使用
Executors.newSingleThreadPool()执行FutureTask<Foo>;那么你将使用这个Future的.get()访问你的Foo -
模式 test-synchronize-set 本质上是不安全的,因为线程 A 可以测试
initialized==false然后在synchronized(this)之前挂起 - 线程 B 然后测试初始化,进行同步,然后启动在里面;然后线程 B 在 I/O 上挂起,线程 A 尝试synchronized(this)并被阻塞,因为 B 仍然有同步。当线程 B 完成并解锁时,线程 A 将继续并再次运行初始化。 -
至少初始化 = true;应该是第一行代码。最好看看单例模式并使用它,即使它不是最好的——出于学术原因,在现实生活中的应用程序中,我已经看到这种初始化工作得很好。我们通过预先接触一个 servlet 来连接做 db,并有一个单例加载资源,但检查更像是 stackoverflow.com/questions/70689/… 和 stackoverflow.com/questions/427902/…
标签: java jakarta-ee tomcat servlets