spring 組件@Scope(request,session)示例

  上回說到, spring組件的註解Scope大約有singleton、prototype、request、session、global session 這麼幾種經常使用的場景。這裏須要特別說明一下,根據源代碼顯示 Scope註解分爲ConfigurableBeanFactory和WebApplicationContext兩個大類,ConfigurableBeanFactory包含(singleton、prototype)兩種Scope,WebApplicationContext下面有(ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,request,session,application,servletContext,contextParameters,contextAttributes)這麼幾種Scope。今天的示例重點是對request,session兩個場景進行一次測試。html

  那在談到具體的示例前,我先分享下對這兩種場景的使用心得,以便與各位看官進行思想上的神交! 咱們都知道B/S站點運行起來後,是一個多線程的運行環境。每一個客戶端登陸都會產生一個session會話,它的生命週期 從登陸系統到 session過時,期間session上存儲的信息都是有效可用的,我習慣於叫它會話級的緩存,像用戶登陸的身份信息咱們通常都會綁定到這個session上。這裏咱們要講的@Scope("session"),就是spring提供出來的一個會話級bean方案,在這種模式下,用spring的DI功能來獲取組件,能夠作到在會話的生命週期中這個組件只有一個實例。接下來再說請求(request),http協議的處理模型,從客戶端發起request請求,到服務端的處理,最後response給客戶端,咱們稱爲一次完整的請求。在這樣的一次請求過程當中,咱們的服務站可能要串行調用funcA->funcB->funcC·... 這樣的一串函數,假如咱們的系統須要作細緻的權限校驗(用戶權限,數據權限),更可怕的是funcA,funcB,funcC是3我的分別實現的,並且都要作權限校驗。那麼極有可能會出現3我的各鏈接了一次數據庫,讀取了同一批權限數據。這裏想象一下,假如一個數據讀取要花2秒,那麼3個方法就要花費6秒的處理時間。但實際上這些數據只用在這個請求過程當中讀取一次,緩存在request上下文環境中,我習慣稱之爲線程級緩存。關於線程級緩存java有ThreadLocal方案,像Hibernate的事務就是用這種方案維持一次執行過程當中數據庫鏈接的惟一。固然,今天要講的@Scope("request")也能夠作到這種線程級別的緩存。下面咱們看看具體的測試示例java

  實現測試步驟說明:spring

 一、建立一個@Scope("session")標註的Bean組件。關於proxyMode這個參數,是爲了解決依存的會話或者請求上下文環境尚未時,自動裝載組件報錯,這裏交給JDK代理,能夠保證環境準備就緒時再執行組件裝載。數據庫

@Component
//@Scope(value=WebApplicationContext.SCOPE_SESSION)
@Scope(value=WebApplicationContext.SCOPE_SESSION,proxyMode=ScopedProxyMode.INTERFACES)
public class SessionBean implements ISessionBean {
   private UUID uuid;
   public SessionBean(){
       uuid = UUID.randomUUID();
   }
   public void printId(){
       System.out.println("SessionBean:"+uuid);
   }
}

 二、建立一個@Scope("request")標註的Bean組件緩存

@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST,proxyMode= ScopedProxyMode.INTERFACES)
public class RequestBean implements IRequestBean {
    private UUID uuid;

    public RequestBean() {
        uuid = UUID.randomUUID();
    }

    public void printId() {
        System.out.println("RequestBean:" + uuid);
    }
}

三、添加一個多例的組件自動組裝服務類,方便獲取session、request組件。session

@Service
@Scope(value=ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class BeanInstance {
    @Autowired
    private IRequestBean requestBean;
    @Autowired
    private ISessionBean sessionBean;
    public IRequestBean getRequestBean() {
        return requestBean;
    }
    public ISessionBean getSessionBean() {
        return sessionBean;
    }
}

四、添加測試代碼多線程

@Controller
@RequestMapping("/user")
// 添加session信息的註解,能夠實現 session信息與map的映射 賦值
@SessionAttributes("user")
public class UserController {
    @Autowired
    private BeanInstance beanInstance1;
    @Autowired
    private BeanInstance beanInstance2;
    
    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String login(String name, Model model, HttpServletRequest request, HttpSession session) {
        model.addAttribute("user", name);
        System.out.println("SessionBean-1");
        beanInstance1.getSessionBean().printId();
        System.out.println("SessionBean-2");
        beanInstance2.getSessionBean().printId();
        System.out.println("RequestBean-1");
        beanInstance1.getRequestBean().printId();
        System.out.println("RequestBean-2");
        beanInstance2.getRequestBean().printId();
        return "user/check";
    }
    /**
     * 檢查自動裝載的信息
     * @param model
     * @param request
     * @param session
     * @return
     */
    @RequestMapping(value = "/check", method = RequestMethod.GET)
    public String check(Model model, HttpServletRequest request, HttpSession session) {
        System.out.println("SessionBean-1");
        beanInstance1.getSessionBean().printId();
        System.out.println("SessionBean-2");
        beanInstance2.getSessionBean().printId();
        System.out.println("RequestBean-1");
        beanInstance1.getRequestBean().printId();
        System.out.println("RequestBean-2");
        beanInstance2.getRequestBean().printId();
        return "user/check";
    }
}

五、先發起一次登陸請求,再發起一次登陸後的檢查請求。從打印的測試結果能夠看到兩次請求 拿到的session組件,其對應的ID都是相同的,因此在同一個會話中,session組件是惟一的。而request組件,在同一個request請求過程當中,調用兩次都獲得同一個組件ID,而在第二次請求中request組件的ID改變了。所以正如上面所說,@Scope("request")模式在同一請求過程當中,spring返回的組件也是惟一的,咱們能夠用這個方案來作線程級別的數據緩存。app

 

參考資料dom

http://www.javashuo.com/article/p-cdfolfba-du.html
http://www.javashuo.com/article/p-zyjkencn-eb.html函數

相關文章
相關標籤/搜索