Проблемы Spring ThreadatingFilterProxy с многопоточностью - PullRequest
4 голосов
/ 07 декабря 2011

При поиске ошибок я наткнулся на исходный код Spring 3.0.5 DelegatingFilterProxy, и мне интересно, несет ли он узкое место в производительности или нет.

Учитывая, что для каждого веб-приложения существует только один экземпляр 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 ]

2 голосов
/ 07 декабря 2011

Вы правы - это похоже на потенциальную проблему, хотя (как отметил Ральф), это не должно быть легко заметным. Они могли бы использовать двойную проверку блокировки (с изменяемым делегатом).

Я бы посоветовал вам создать проблему весной jira. Если нет - я сделаю это.

1 голос
/ 17 декабря 2015

Это было исправлено с двойной проверкой в ​​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

1 голос
/ 07 декабря 2011

Для меня это похоже на некоторый код инициализации.После первого запуска this.delegate имеет значение, отличное от null.Тогда в синхронизированном блоге остаются только две отметки if (this.delegate == null) и delegateToUse = this.delegate.

Этот блок выполняется один раз для каждого запроса, поэтому: НЕТ, это не влияет на производительность веб-приложения, котороеможно измерить.

Конечно, Божо прав, это можно сделать лучше.Но вы никогда не заметите разницу в производительности: если на сервере будет достаточно нагрузки, чтобы этот sycronized-блок имел измеряемое влияние, то все остальное на этом сервере уже полностью перегружено .

...