Spring продвижение запроса с областью действия для дочерних потоков (HttpServletRequest)

Я пробовал много вещей сейчас, но я, кажется, пропустил часть головоломки. Вот история: у меня есть боб с областью запроса, который читает некоторый SessionContext из HttpServletRequest. Этот атрибут задается в фильтре. Таким образом, это работает абсолютно нормально, пока код работает в правильном потоке.

@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.INTERFACES)
public class SessionContextProviderImpl implements SessionContextProvider<SessionContext> {
    private final HttpServletRequest _request;

    @Autowired
    public SessionContextProviderImpl(HttpServletRequest request) {
        _request = request;
    }

    @Override
    public SessionContext get() {
        return (SessionContext) _request.getAttribute(Constants.SESSION_CONTEXT_IDENTIFIER);
    }
}

Теперь я начал использовать новую функцию Java 8s CompletableFuture, и у меня есть три из этих функций, вычисляющих материал параллельно, пока поток запроса ждет результата. То, что я хочу сделать, это продвигать/передавать/распространять компонент или запрос таким образом, чтобы он мог использоваться в дочерних потоках, которые были порождены из исходного http-потока. В частности, я хотел бы получить SessionContext из HttpServletRequest изнутри асинхронной поставляемой CompletableFuture.

то, что я пробовал, это (замененная реализация get):

final HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
request.getAttribute(Constants.SESSION_CONTEXT_IDENTIFIER);

но это, очевидно, имеет тот же результат, что и Боб области запроса. Ну "getRequest" возвращает null вместо исключения.

в качестве третьего подхода я попытался это оригинальное сообщение:

ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory;

org.springframework.beans.factory.config.Scope simpleThreadScope = new SimpleThreadScope();

cbf.registerScope("simpleThreadScope", simpleThreadScope);

и я установил область действия SessionContextProviderImpl как "simpleThreadScope". К сожалению, это тоже не сработало и вызвало исключение, что оно используется вне области запроса.

окружающая среда я использую: Джерси вместе с впрыской весны.

может быть, у кого-то есть идея?

в отношении

1 ответов


для будущих авантюристов:

Я потратил некоторое время, чтобы покопаться в коде Весны и нашел RequestContextHolder который имеет inheritableRequestAttributesHolder. Если вы посмотрите на документацию о том, что это такое (наследуется от:InheritableThreadLocal) можно прочитать следующее:

наследуемые локальные переменные потока используются в предпочтении обычным локальным переменным потока, когда атрибут per-thread поддерживается в переменная (например, идентификатор пользователя, идентификатор транзакции) должна автоматически передаваться любым созданным дочерним потокам.

Так RequestContextHolder имеет поле для этого и фактически setRequestAttributes поддерживает флаг для использования inheritableRequestAttributesHolder. Кроме того, если вы посмотрите на RequestContextListener -> requestInitialized вы обнаружите, что он вызывается без флага (= false). В итоге я сделал вот что:--2-->

public class InheritableRequestContextListener extends RequestContextListener {
    private static final String REQUEST_ATTRIBUTES_ATTRIBUTE =
        InheritableRequestContextListener.class.getName() + ".REQUEST_ATTRIBUTES";

    @Override
    public void requestInitialized(ServletRequestEvent requestEvent) {
        if (!(requestEvent.getServletRequest() instanceof HttpServletRequest)) {
            throw new IllegalArgumentException(
                    "Request is not an HttpServletRequest: " + requestEvent.getServletRequest());
        }
        HttpServletRequest request = (HttpServletRequest) requestEvent.getServletRequest();
        ServletRequestAttributes attributes = new ServletRequestAttributes(request);
        request.setAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE, attributes);
        LocaleContextHolder.setLocale(request.getLocale());
        RequestContextHolder.setRequestAttributes(attributes, true);
    }
}

и вуаля, я могу открыть SessionContextProvider в потоках ребенка.