Spring DelegatingFilterProxy涉及多线程问题

时间:2011-12-07 14:49:17

标签: multithreading spring java-ee servlet-filters

在查找错误时,我遇到了Spring 3.0.5源代码DelegatingFilterProxy,我想知道它是否存在性能瓶颈。

鉴于每个Web应用程序只有一个DelegatingFilterProxy实例(当然是每个<filter>声明)我必须假设在高负载下很多工作线程都试图调用doFilter()方法并行。

现在看一下代码:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {

    // Lazily initialize the delegate if necessary.
    Filter delegateToUse = null;
    synchronized (this.delegateMonitor) {
        if (this.delegate == null) {
            WebApplicationContext wac = findWebApplicationContext();
            if (wac == null) {
                throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener registered?");
            }
            this.delegate = initDelegate(wac);
        }
        delegateToUse = this.delegate;
    }

    // Let the delegate perform the actual doFilter operation.
    invokeDelegate(delegateToUse, request, response, filterChain);
}

synchronized (this.delegateMonitor)块必须由所有线程传递,这意味着所有工作人员都被迫耐心排队,直到他们被允许进入。

无论为什么需要在这里完成bean查找,我怀疑可以避免使用synchronized以支持并行执行 - 可能是通过使this.delegate为volatile而仅使用同步需要完成查找的情况。

我在吠叫错误的树吗?任何意见都表示赞赏。

3 个答案:

答案 0 :(得分:2)

你是对的 - 这似乎是一个潜在的问题,alghouth(正如拉尔夫所指出的那样),它应该不容易被人注意到。他们可以使用双重检查锁定(使用易失性委托)。

我建议你在春季jira中创建一个问题。如果你不这样做 - 我会做的。

答案 1 :(得分:1)

对我来说,它看起来像是一些初始化代码。第一次运行后this.delegate的值与null不同。然后,同步博客中只剩下两个if (this.delegate == null)delegateToUse = this.delegate个数据。

每个请求执行一次此块,因此:NO它不会影响可以测量的Web应用程序的性能。

当然Bozho是对的,它可以做得更好。但是你永远不会注意到性能上的差异 - 如果服务器上有足够的负载使得这个sycronized块会产生可测量的影响,那么这个服务器上的其他任何东西都已经完全超载了

答案 2 :(得分:1)

在Spring 4中通过双重检查修复了这个问题

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {

    // Lazily initialize the delegate if necessary.
    Filter delegateToUse = this.delegate;
    if (delegateToUse == null) {
        synchronized (this.delegateMonitor) {
            if (this.delegate == null) {
                WebApplicationContext wac = findWebApplicationContext();
                if (wac == null) {
                    throw new IllegalStateException("No WebApplicationContext found: " +
                            "no ContextLoaderListener or DispatcherServlet registered?");
                }
                this.delegate = initDelegate(wac);
            }
            delegateToUse = this.delegate;
        }
    }

    // Let the delegate perform the actual doFilter operation.
    invokeDelegate(delegateToUse, request, response, filterChain);
}

见提交
https://github.com/spring-projects/spring-framework/commit/c26272cef62b1e6f3bb982d7f71b2f47c685b014

见JIRA https://jira.spring.io/browse/SPR-10413