RequestContextHolder源码理解使用

Posted dlage

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RequestContextHolder源码理解使用相关的知识,希望对你有一定的参考价值。

首先看这个类的变量:

    private static final boolean jsfPresent = ClassUtils.isPresent("javax.faces.context.FacesContext", RequestContextHolder.class.getClassLoader());
    private static final ThreadLocal<RequestAttributes> requestAttributesHolder = new NamedThreadLocal("Request attributes");
    private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder = new NamedInheritableThreadLocal("Request context");

使用了两个ThreadLocal来存储当前线程下的request。

对于ThreadLocal可以看相应的笔记。

看看这个ThreadLocal类是怎么获取request的。在类中直接调用了ThreadLocal的get()方法,该方法会判断,如果当前线程的ThreadLocalMap存在,就直接使用这个ThreadLocalMap,ThreadLocalMap里面存放着当前线程的信息。如果当前线程的ThreadLocalMap不存在就创建一个新的ThreadLocalMap,并保存。

@Nullable
public static RequestAttributes getRequestAttributes() {
    RequestAttributes attributes = (RequestAttributes)requestAttributesHolder.get();
    if (attributes == null) {
        attributes = (RequestAttributes)inheritableRequestAttributesHolder.get();
    }

    return attributes;
}

他会返回一个T对象,就是我们RequestContextHolder的变量ThreadLocal,将RequestAttributes返回。使用ThreadLocal实现线程隔离。

public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}

具体的使用:

在代码中,我们并不会使用RequestAttributes,可以看看下面的RequestAttributes类,里面的方法太少了,我们没有使用框架之间都会使用servlet包下的HttpServletRequest。所以我们要将它转换成ServletRequestAttributes。它是Spring提供操作HttpServletRequest的类。

ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
public interface RequestAttributes {
    int SCOPE_REQUEST = 0;
    int SCOPE_SESSION = 1;
    String REFERENCE_REQUEST = "request";
    String REFERENCE_SESSION = "session";

    @Nullable
    Object getAttribute(String var1, int var2);

    void setAttribute(String var1, Object var2, int var3);

    void removeAttribute(String var1, int var2);

    String[] getAttributeNames(int var1);

    void registerDestructionCallback(String var1, Runnable var2, int var3);

    @Nullable
    Object resolveReference(String var1);

    String getSessionId();

    Object getSessionMutex();
}

我们来看一下ServletRequestAttributes,在ServletRequestAttributes类里面有一个HttpServletRequest request变量,看到这个变量我们应该熟悉怎么去操作它了。

public class ServletRequestAttributes extends AbstractRequestAttributes {
    public static final String DESTRUCTION_CALLBACK_NAME_PREFIX = ServletRequestAttributes.class.getName() + ".DESTRUCTION_CALLBACK.";
    protected static final Set<Class<?>> immutableValueTypes = new HashSet(16);
    private final HttpServletRequest request;
    @Nullable
    private HttpServletResponse response;
    @Nullable
    private volatile HttpSession session;
    private final Map<String, Object> sessionAttributesToUpdate;

以上是关于RequestContextHolder源码理解使用的主要内容,如果未能解决你的问题,请参考以下文章

使用RequestContextHolder.getRequestAttributes()的注意事项

Spring中RequestContextHolder以及HandlerInterceptorAdapter的使用

RequestContextHolder getHttpServletRequest

RequestContextHolder与RequestContextUtils

RequestContextHolder.getRequestAttributes() null - Spring Security + Multi Tenant [关闭]

RequestContextHolder.getRequestAttributes()null - Spring Security + Multi Tenant [关闭]