У меня проблемы с доступом к bean-компоненту, который определен с областью, ориентированной на запрос, в потоке, который не является потоком запроса.
Мой сценарий выглядит следующим образом:
Выполнение начинается с запроса REST, поступающего от клиента.В этом запросе я определяю компонент, который позволяет мне получать доступ к данным в БД.Расположение БД зависит от пользователя, выполняющего сам запрос, следовательно, почему bean-компонент, к которому осуществляется доступ к БД, связан с самим запросом.Я получаю данные пользователя из авторизации запроса и использую их для инициализации компонента.
Во время HTTP-запроса код может вызывать внешнюю службу через соединение через веб-сокет.Трафик ws обрабатывается различными StompFrameHandler
классами.Когда они обрабатывают трафик, они делают это в выделенном потоке, который не совпадает с первоначальным запросом http (и это справедливо!).
- Некоторым из этих
StompFrameHandler
классов необходим доступ к БДактуально для пользователя в контексте текущего (REST) запроса.
В точке 3 я сталкиваюсь с проблемой:
Нет запроса с привязкой к потоку: Вы ссылаетесь на атрибуты запроса вне фактического веб-запроса или обрабатываетезапросить за пределами изначально полученного потока?Если вы действительно работаете в веб-запросе и по-прежнему получаете это сообщение, ваш код, вероятно, выполняется за пределами DispatcherServlet / DispatcherPortlet: в этом случае используйте RequestContextListener или RequestContextFilter для предоставления текущего запроса.
Iпонять, что говорит мне ошибка, и тот факт, что из-за того, как я определил свой bean-компонент (ограниченный областью действия запроса), Spring не позволяет мне обращаться к нему в других потоках.Однако мне все еще нужно использовать этот компонент доступа к базе данных из потока обработки трафика ws.
Вот упрощенная версия моего кода:
Конфигурация компонента:
@Configuration
public class DbClientRequestScopeConfiguration {
private DbClientFactoryI dbClientFactory;
private AuthenticationFacadeI authenticatedUserInfo;
@Autowired
public DbClientRequestScopeConfiguration(DbClientFactoryI dbClientFactory, AuthenticationFacadeI authenticatedUserInfo) {
this.dbClientFactory = dbClientFactory;
this.authenticatedUserInfo = authenticatedUserInfo;
}
@Bean
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public DbClientI getDbClient() {
Authentication auth = authenticatedUserInfo.getAuthentication();
return dbClientFactory.getDbClient(auth.getDetails());
}
}
Служба DataService с использованием компонента (выполняется в потоке запроса)
@Service
public class DataService {
private DbClientI dbClient;
@Autowired
public DataService(DbClientI dbClient) {
this.dbClient = dbClient;
}
...
}
Обработчик фрейма, работающий с трафиком WS Обратите внимание, что это не инициализируется в контексте Spring, вместо этого он инициализируется вручную классомвыполняется в потоке запроса, который дает ему экземпляр @DataService из контекста.
public class SaveDataFrameHandler implements StompFrameHandler{
private DataService dataService;
public SaveDataFrameHandler(DataService dataService) {
this.dataService = dataService;
}
@Override
public Type getPayloadType(StompHeaders headers) {
return JsonNode.class;
}
@Override
public void handleFrame(StompHeaders headers, Object payload) {
// This method will be called on a separate thread
JsonNode jsonPayload = (JsonNode) payload;
dataService.saveRecord(jsonPayload);
}
}
Я ищу предложения о том, как на самом деле использовать этот bean-компонент в моем потоке ws или как изменить архитектуру решения, чтобы я не столкнулся с этой проблемой.
Спасибо зазаранее!
ОБНОВЛЕНИЕ:
Пока мне удалось обойти проблему, хотя я не на 100% доволен решением.Чтобы избежать повторения, я опубликовал свое текущее решение в новом вопросе, поскольку я сталкиваюсь с другой проблемой, которая все еще связана с этим кодом: Прокси-компонент-прототип создается каждый раз, когда из него вызывается метод