Должен ли я поместить свои ThreadLocals в подпружиненный синглтон? - PullRequest
14 голосов
/ 07 февраля 2010

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

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

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

@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 - это объявление о том, что этот класс использует эту переменную.

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

Ответы [ 4 ]

19 голосов
/ 08 февраля 2010

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

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

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

Таким образом, чтобы посоветовать подход, если у вас есть веб-приложение Spring с bean-компонентами Spring, которые хотят получить доступ к объектам, специфичным для текущего потока запроса, я бы посоветовал использовать bean-объекты в области запроса. Если вам нужно получить доступ к этим объектам вне контроля bean-компонентов Spring, тогда ThreadLocal может быть проще, хотя я бы постарался сделать так, чтобы объекты работали с bean-объектами в максимально возможной степени.

11 голосов
/ 08 февраля 2010

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

public interface UserName {
    ...
}

@Component 
@Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
public class UsernameImpl implements UserName { 
    private String username; 
    ...
}
6 голосов
/ 08 февраля 2010

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

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

1 голос
/ 16 января 2017

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...