1. 程式人生 > >由SpringMVC中RequetContextListener說起

由SpringMVC中RequetContextListener說起

listener attribute 請求 bool 程序 div n) https 操作

零、引言

RequetContextListener從名字結尾Listener來看就知道屬於監聽器。 所謂監聽器就是監聽某種動作,在其開始(初始化)和結束(銷毀)的時候進行某些操作。 由此可以猜測:該類用於在RequetContext(請求上下文對象)創建和銷毀的時候進行某些操作(哪些操作?結尾總結!)

一、web.xml配置

要使用該listener對象需要在web.xml中進行如下配置。
<!-- 此監聽器是監聽HttpRequest對象,方便ContextHolderUtils程序調用HttpRequest對象 -->
<listener>
<description>request監聽器</description>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>

二、三個重要類解讀

2.1 RequetContextListener

技術分享
public class RequestContextListener implements ServletRequestListener {
    private static final String REQUEST_ATTRIBUTES_ATTRIBUTE =
            RequestContextListener.class.getName() + ".REQUEST_ATTRIBUTES";
    // 在請求進入的時候,初始化變量放入ThreadLocal<T>中
    @Override
    public void requestInitialized(ServletRequestEvent requestEvent) {
        //判定當前的requetEvent中獲取的ServletRequest()對象是否是HttpServletRequet對象
        if (!(requestEvent.getServletRequest() instanceof HttpServletRequest)) {
            throw new IllegalArgumentException(
                    "Request is not an HttpServletRequest: " + requestEvent.getServletRequest());
        }
        //強制轉型為 HttpServletRequest
        HttpServletRequest request = (HttpServletRequest) requestEvent.getServletRequest();
        // ServletRequestAttributes 保存了HttpServletRequet、Response、Session等變量
        ServletRequestAttributes attributes = new ServletRequestAttributes(request);
        request.setAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE, attributes);
        LocaleContextHolder.setLocale(request.getLocale());
        //RequestContextHolder裏面有一個ThreadLocal,當前線程共享
        RequestContextHolder.setRequestAttributes(attributes);
    }
    //在請求被銷毀的時候,將在初始化時候的ThreadLocal變量清空。
    @Override
    public void requestDestroyed(ServletRequestEvent requestEvent) {
        ...
    }
}
技術分享

2.2 RequetContextHolder

技術分享
public abstract class RequestContextHolder  {
    //ThreadLocal<T>變量用於保存當前線程的共享變量
    private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
            new NamedThreadLocal<RequestAttributes>("Request attributes");
    private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder =
            new NamedInheritableThreadLocal<RequestAttributes>("Request context");
    /**
     * 將線程中的共享變量清除掉,會在RequetContextListner的destory()方法中調用。
     */
    public static void resetRequestAttributes() {
        //清空變量
        requestAttributesHolder.remove();
        inheritableRequestAttributesHolder.remove();
    }
    //過渡方法
    public static void setRequestAttributes(RequestAttributes attributes) {
        setRequestAttributes(attributes, false);
    }
    // 核心的方式:將RequetAttrubutes(Request/Response/Session)放入到ThreadLocal<T>中進行共享
    public static void setRequestAttributes(RequestAttributes attributes, boolean inheritable) {
        if (attributes == null) {
            resetRequestAttributes();
        }
        else {
            if (inheritable) {
                inheritableRequestAttributesHolder.set(attributes);
                requestAttributesHolder.remove();
            }
            else {
                requestAttributesHolder.set(attributes);
                inheritableRequestAttributesHolder.remove();
            }
        }
    }
技術分享

2.3 ServletRequestAttributes

技術分享
public class ServletRequestAttributes extends AbstractRequestAttributes {
    private final HttpServletRequest request;
    private HttpServletResponse response;
    private volatile HttpSession session;
    private final Map<String, Object> sessionAttributesToUpdate = new ConcurrentHashMap<String, Object>(1);
}
技術分享

三、使用方法

從以上可以知道RuquetAttribute是放在了ThreadLocal中,則在該次請求中,可以在任意的代碼位置中獲取該該對象,由此拿到HttpServletRequet等對象。
HttpServletRequest request =((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
利用該方法可以在任意位置獲取request對象.

四、總結

RequetContextListner主要作用就一個: 將本次請求的 ServletRequestAttributes 對象 保存在ThreadLocal中,方便在某一次請求的任意代碼位置獲取(包括直接在service層獲取)。

http://www.cnblogs.com/LiuChunfu/p/7067828.html

由SpringMVC中RequetContextListener說起