2011-12-07 90 views
4

尋找錯誤時,我遇到了Spring 3.0.5源代碼DelegatingFilterProxy,我不知道它是否存在性能瓶頸。Spring 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查找我懷疑使用​​本來是可以避免利於並行執行的 - 可以是僅在查找的情況下,使this.delegate揮發性和使用同步需要做的。

所以,我吠叫錯了樹?任何輸入讚賞。

回答

2

你說得對 - 這似乎是一個潛在的問題,alghouth(正如拉爾夫指出的那樣),它不應該很容易知道。他們可能使用了雙重檢查鎖定(使用volatile代理)。

我建議你在春季吉拉創建一個問題。如果你不這樣做 - 我會做的。

+0

我沒有這樣做呢。隨意這樣做。關於性能的影響,我記得我心愛的Java實踐中的「Java Concurrency」一書中說,掛起和重新激活線程在時鐘週期中與對象分配等相比是巨大的。同樣看着像AtomicLong或ConcurrentHashMap這樣的類,它們儘可能地避免了同步塊,這給了我相同的方向。 – user1085804

1

對我來說,它看起來像一些初始化代碼。第一次運行後this.delegate的值與null不同。然後,在同步博客中只剩下兩個陳述if (this.delegate == null)delegateToUse = this.delegate

該塊每個請求執行一次,所以:NO不會影響可測量的Web應用程序的性能。

當然bozho是對的,它可以做得更好。但是您永遠不會注意到性能的差異 - 如果服務器上有足夠的負載,以便此sycronized塊會產生測量影響,則此服務器上的其他所有設備已經完全超載

+0

感謝您的回覆。關於負載,我們很幸運地在Oracles Exadata上進行負載測試,在那裏我們看到類似的代碼成爲真正的瓶頸。所以我爲自己脫身,以避免有超過幾個線程訪問它的機會。 – user1085804

1

這已被固定雙重檢查春季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