Должен ли я помещать свои ThreadLocals в spring -инъекционный синглтон?

Несколько человек (например, на serveride http://www.theserverside.com/news/thread.tss?thread_id=41473) предполагают, что использование объектов ThreadLocal так же плохо, как использование глобальных переменных. Я предполагаю, что это верно, если вы делаете их общедоступными статическими переменными. Тогда проблема заключается в том, что трудно определить, где она используется, где она изменилась и т.д.

В моем веб-приложении spring DI tomcat, похоже, это противостоит этой проблеме, если я просто получаю spring для создания одноэлементного объекта, в котором есть мои ThreadLocal (ы), а затем вставляют этот singleton в любой класс которому это необходимо.

Итак, мой синглтон выглядит так:

@Component
public class Username {
    private ThreadLocal<String> username;

    public Username() {
        username = new ThreadLocal<String>();
    }

    public String getUsername()
        return username.get();
    }

    public void setUsername(String name) {
        username.set(name);
    }
}

И классы, которые могут понадобиться, выглядят следующим образом:

@Service
public class addEntryTransaction {

    @Autowired
    Username username;

    public void method() {
        ...
        log("Method called by "+username.getUsername());
        ...
     }

}

Это по-прежнему имеет преимущество в том, что вам не нужно пропускать имя пользователя через множество слоев, которые не заботятся, и, следовательно, упрощение параметров метода. @Autowired - это объявление, которое этот класс использует эту переменную.

Каковы преимущества и недостатки этого подхода?

Ответы

Ответ 1

Если вы используете Spring, вы можете просто использовать bean с ограниченным запросом вместо явного ThreadLocal s:

public interface UserName {
    ...
}

@Component 
@Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
public class UsernameImpl implements UserName { 
    private String username; 
    ...
}

Ответ 2

Как упоминалось в @axtavt, с запросом beans обычно являются более чистой и более элегантной альтернативой ThreadLocals, когда вы говорите о сети Приложения. Фактически, под обложками Spring реализует область beans с областью запроса с использованием собственных переменных ThreadLocal (см. RequestContextHolder). Как ThreadLocal, так и scoped beans дают вам одно и то же основное преимущество - возможность доступа к объекту без необходимости передавать его вручную через стек вызовов.

Существует один сценарий, когда variales ThreadLocal перехватывают область beans, хотя это происходит в тех случаях, когда вы хотите получить доступ к объекту из-за Spring bean жизненного цикла. Хорошим примером этого является JBL taglib. Экземпляры Taglib контролируются контейнером сервлета, а не Spring, и поэтому не могут участвовать в структуре IoC Spring IoC, поэтому его нельзя подключить с помощью bean с запросом (или любого другого bean, если на то пошло). Однако они могут получить доступ к переменным ThreadLocal. Есть способы обойти это, но иногда ThreadLocals - самый простой подход.

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

Поэтому, чтобы сообщить о подходе, если у вас есть Spring webapp, с Spring beans, которые хотят получить доступ к объектам, которые относятся к текущему потоку запросов, тогда я бы посоветовал использовать beans. Если вам нужно получить доступ к этим объектам, находящимся вне контроля Spring beans, то ThreadLocal может быть проще, хотя я бы старался максимально эффективно работать с областью beans.

Ответ 3

Spring использует ThreadLocal внутренне, и нет ничего плохого в том, чтобы иметь их как инфраструктуру. Однако вы должны избегать их для бизнес-логики.

Если они вам действительно нужны, а область request вам не подходит (по какой-то непредвиденной причине), я бы посоветовал определить пользовательский Scope, используя ThreadLocal внутренне, тем самым скрывая его от вашего бизнес-логика.

Ответ 4

ThreadLocals отлично работают, когда у вас есть общий код, который обрабатывается JMS, Queues и http-запросами. Запросить значения области не работают во всех сценариях.

Одна важная вещь, которую следует помнить при использовании threadLocals, заключается в том, что потоки будут повторно использоваться контейнером сервера, так же как и локальные значения переменных, если на нем установлено что-то, если у вас есть значения, которые должны быть reset, используйте сервлет-фильтры/объекты прокси-сервера AOP на прослушивателях контроллеров /jms, чтобы очистить значения непосредственно перед тем, как он вызывает бизнес-логику, или же вы можете в конечном итоге отлаживать очень трудно, чтобы воспроизвести тип проблем.