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