Spring自定义请求上下文

use*_*676 2 java spring spring-mvc

Spring提供的作用域之一是request,其中的bean仅在请求的上下文中有效。

在 HTTP 请求之后,该请求通常会委托给控制器,并且 Spring 已经设置了所有必要的内容。

但是,如果请求来自不同的源(例如 Java 消息服务)怎么办?

是否可以为消息的每次处理设置一个请求范围?

我可以用一些东西注释一个方法以将其标记为请求范围的边界吗?

Ken*_*han 5

在幕后,Spring 只是在处理 HTTP 请求时在开始时调用RequestContextHolderset RequestAttributesto ,并在该线程处理完请求之前将其删除。请求和会话范围 bean 实际上存储在 this 中并从中获取。ThreadLocalThreadLocalRequestAttributes

在正常的 Web 情况下,此RequestAttributes实现由HttpServletRequest. 但是,在非 Web 环境中,没有HttpServletRequest,因此您不能使用现有的实现。其中一种方法是实现RequestAttributes由内部映射支持的 :

public class InMemoryRequestAttributes extends AbstractRequestAttributes {

    protected Map<String, Object> attributes = new HashMap<>();


    @Override
    public Object getAttribute(String name, int scope) {
        return attributes.get(name);
    }

    @Override
    public void setAttribute(String name, Object value, int scope) {
        attributes.put(name, value);
    }

    @Override
    public void removeAttribute(String name, int scope) {
        attributes.remove(name);
    }

    @Override
    public String[] getAttributeNames(int scope) {
        String[] result = new String[attributes.keySet().size()];
        attributes.keySet().toArray(result);
        return result;
    }

    @Override
    public void registerDestructionCallback(String name, Runnable callback, int scope) {
        synchronized (this.requestDestructionCallbacks) {
            this.requestDestructionCallbacks.put(name, callback);
        }

    }

    @Override
    public Object resolveReference(String key) {
        return attributes;
    }

    @Override
    public String getSessionId() {
        return null;
    }

    @Override
    public Object getSessionMutex() {
        return null;
    }

    @Override
    protected void updateAccessedSessionAttributes() {

    }

}
Run Code Online (Sandbox Code Playgroud)

注意:它仅适用于请求范围 bean。如果您也想支持会话范围 bean,请修改它......

然后设置它并从ThreadLocal之前删除它并完成 JMS 消息的处理,如下所示:

public void receive(String message){
    RequestContextHolder.setRequestAttributes(new InMemoryRequestAttributes());
    fooBean.processMessage(message);
    RequestContextHolder.resetRequestAttributes();
}
Run Code Online (Sandbox Code Playgroud)