2013-09-24 3 views
4

Нужна помощь с пружинным автоуведомлением и областями.Spring @Autowired - Создать новый bean-компонент

Вот основная структура приложения:

  1. У меня есть CustomHttpClient, аннотированный, как @Component, а также вытягивать некоторые конфигурационные свойства, связанные с application.properties файла (через @value аннотацию).

  2. CustomHttpClient используется несколькими службами в моем приложении. Всякий раз, когда я использую CustomHttpClient, я autowire экземпляр, который с помощью:

    @Autowired 
    private CustomHttpClient httpClient; 
    
  3. Я использую перехватчик для изменения некоторых переменных внутри CustomHttpClient, например, так:

    public class MyInterceptor extends HandlerInterceptorAdapter { 
    @Autowired CustomHttpClient httpClient; 
    
    @Override 
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 
    httpClient.setSomeProperty(newValue); 
    ... 
    

сейчас , вот в чем проблема. Если у меня все настроено так, как описано выше, то всякий раз, когда я изменяю любой параметр CustomHttpClient через перехватчик, это новое значение сохраняется для всех других клиентов, пока работает VM. Поэтому, когда я запускаю httpClient.setSomeProperty(), этот параметр теперь сохраняется навсегда. Даже если я подключаюсь к приложению от другого клиента.

В основном то, что мне нужно иметь две вещи:

  1. Еще будучи в состоянии переопределить настройки по умолчанию с помощью CustomHttpClient перехватчик (запрос перехватчик, сконфигурированные с помощью).
  2. Убедитесь, что для каждого запроса создается новый экземпляр CustomHttpClient (после того, как перехватчик делает свое «волшебство»).

Я попытался изменить область CustomHttpClient на @Scope («прототип»), но таким образом я больше не могу изменять настройки CustomHttpClient с помощью перехватчика.

+1

Возможно, я ошибаюсь, но я думаю, что дизайн, вероятно, испорчен, если вам нужна инъекция для этого прототипического многоразового компонента, свойства которого необходимо изменить для каждого запроса. Возможно, лучше всего, если вы контролируете создание и уничтожение вручную. В конце концов, не все объекты должны быть введены. –

+0

Хммм, это может быть хорошим моментом. Но если я не буду автоувеличивать и не вставлять компонент, смогу ли я все же отрегулировать его свойства с помощью перехватчика? Допустим, у меня нет контроля над фактическим сервисом, который использует этот компонент, и может изменять только некоторые свойства через HTTP-заголовки и/или параметры строки запроса. Это была основная причина, по которой я ездил с автоматом. – isyndicate

+0

Если вам просто нужно настроить заголовки и/или параметры, почему бы вам просто не изменить «HttpServletRequest' /' HttpServletResponse »? Вот почему они доступны вам в перехватчике. – Aurand

ответ

6

По умолчанию, когда вы используете @Autowired весна бобы scope Singleton. Это означает, что весна вводит один и тот же одноэлементный объект, где вы используете @Autowired. Сделав область prototype, вы инструктируете Spring создавать новые объекты для каждой @Autowired инъекции, и поэтому ваш перехватчик будет иметь свою собственную копию HttpClient и не может видеть другие объекты HttpClient.

Таким образом, лучший подход - использовать область singleton, использовать атрибуты запроса или threadlocal для переноса ваших пользовательских свойств в поток запросов. т.е. вместо изменения свойств HttpClient в перехватчике, просто установите некоторые атрибуты запроса или threadlocals и обработайте эти пользовательские настройки в пределах методов класса CustomHttpClient.

1

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

Таким образом вам не нужен новый экземпляр HttpcLient каждый раз, а новый экземпляр каждый раз будет серьезным недостатком. И вы сможете использовать свою собственную карту в любом месте в текущем потоке.

+1

'ThreadLocal' похоже на очень тяжелый подход к этой проблеме. Если вы собираетесь использовать локаторы потоков, вы ДОЛЖНЫ убедиться, что их не удалите (по-видимому, я имею в виду очень осторожное и предполагаемое использование блоков finally). – Aurand

+0

@Aurand Ya Необходимо обязательно отключить значение из локального потока, который может быть легко обеспечен путем создания настраиваемого Session Keeper, который можно вызвать при входе и выходе. Но это дает преимущества с точки зрения удобства доступа. –

1

Все бобы, объявленные в контейнере Spring контейнером XML или поддержкой аннотаций, по умолчанию являются одиночными.Если вы введете бонус с областью действия, установленной для прототипа, в одноэлементный, например. контроллер будет вводить его только один раз. Существует способ достижения этой цели. Вот как вы должны объявить bean-область как прототип. Это означает, что контейнер всегда будет давать вам новый экземпляр каждый раз, когда этот компонент вызывается из контейнера.

<bean id="shoppingCart" class="example.ShoppingCart" scope="request"> 
    <aop:scoped-proxy /> 
</bean> 
+0

Как я уже упоминал в своем вопросе, я попытался использовать область прототипа, но это побеждает цель автоувеличивания и впрыскивания свойств через перехватчик. Поскольку в качестве прототипа каждый раз создается новый экземпляр, поэтому теряются любые изменения, сделанные из перехватчика. – isyndicate