程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> JSF請求處理過程(二) 請求處理過程總覽(FacesServlet#service)

JSF請求處理過程(二) 請求處理過程總覽(FacesServlet#service)

編輯:關於JAVA

這總覽,很明顯是看FacesServlet的service方法。在 FacesServlet的初始化過程中,構造出了全局的FacesContextFactory對象和LifeCycle對象。可以把 FacesContextFactory看做是一個“請求包裝工廠”,於是很明顯,每當一個請求到達FacesServlet的時候,第一步便是拿著請求,到包裝工廠裡面包裝一下,而包裝的結果就是一個FacesContext。代碼如下:

1 FacesContext context = facesContextFactory.getFacesContext(servletConfig.getServletContext(), request, response, lifecycle); 

在包裝過程中,實際上是創建了一個com.sun.faces.context.FacesContextImpl對象,FacesContextImpl類繼承了jsf-api項目中的javax.faces.context.FacesContext。 FacesContextImpl的構造方法的第一個參數是一個叫做ExternalContext的接口的實現,查看其源代碼,可以看到 ExternalContextImpl類耦合了Servlet API,而FacesContextImpl與Servlet API無關。實際上,在這裡,做到了JSF可以不僅僅使用在Servlet環境中,正如ExternalContext接口的注釋中所說,在 Servlet環境中使用JSF和在Portlet環境中使用JSF的不同,實際上就是使用了不同的ExternalContext。在 FacesContextFactoryImpl中構造FacesContextImpl的代碼如下:

1 FacesContext ctx = new FacesContextImpl(new ExternalContextImpl((ServletContext) sc,(ServletRequest) request,(ServletResponse) response),lifecycle);

FacesContextImpl的構造方法中,還做了另外一件事情,就是根據配置確定了RenderKitFactory,顯然不同的 RenderKitFactory可以產生不同的RenderKit,而不同RenderKit對象是針對不同客戶端的,所以對於浏覽器、移動設備等等,會有不同的RenderKit。FacesContextImpl的構造方法中代碼如下:

1 this.externalContext = ec;
2 setCurrentInstance(this);
3 this.rkFactory = (RenderKitFactory)FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);

在代碼中我們經常使用FacesContext.getCurrentInstance()這個靜態方法來獲取與當前請求對應的 FacesContext對象,實際上是在FacesContext類裡面有一個靜態的ThreadLocal對象用來存放了當前請求線程對應的 FacesContext對象,於是上面的代碼中setCurrentInstance(this)就是把當前構造出來的這個FacesContext對象放到了ThreadLocal裡面。

FacesContext創建出來以後,正如上面所說,要讓他經過LifeCycle這個“Filter Chain”的逐步處理了。那麼,Filter Chain裡面放的是一個一個Filter,那麼LifeCycle這個Chain裡面放的是什麼呢?答案是Phases。

FacesServlet讓FaceContext通過LifeCycle的處理,分成了兩個部分。一個部分是調用LifeCycle的 execute方法,執行邏輯,第二個部分是調用LifeCycle的render方法,呈現響應。FacesServlet.service中代碼如下:

1 lifecycle.execute(context);
2 lifecycle.render(context);

在LifeCycleImpl這個實現中,存放了一個Phase對象的數組,存放了7個Phase。其中第一個是null,然後依次是視圖重建、應用請求值、驗證、更新模型值、執行應用程序、呈現響應。在execute方法中,調用了從視圖重建開始到執行應用程序為止的5個Phase,而在 render方法中,調用了最後一個Phase,也就是呈現響應。在LifeCycleImpl類中,代碼如下:

//The Phase instance for the render() method
     private Phase response = new RenderResponsePhase();
     // The set of Phase instances that are executed by the execute() method
     // in order by the ordinal property of each phase
     private Phase[] phases = {
         null, // ANY_PHASE placeholder, not a real Phase
         new RestoreViewPhase(),
         new ApplyRequestValuesPhase(),
         new ProcessValidationsPhase(),
         new UpdateModelValuesPhase(),
         new InvokeApplicationPhase(),
         response
     };

在Servlet Filter中,可以由每一個Filter來決定是否要調用下一個Filter,從而決定是否讓請求繼續通過Filter Chains中的後續Filter,是鏈式調用的過程。而在LifeCycle的execute方法中,是用一個for循環順序執行幾個Phase。在每一個Phase執行完之後,都會檢查FaceContext對象中是否設置了停止後續處理直接呈現響應的標志(renderResponse)或者已經完成了響應無需後續處理也不需要經過呈現響應階段了(responseComplete),如果標志為true,那麼就不再執行後續Phase。

LifeCycleImpl的execute方法主要代碼如下:

1 for (int i = 1, len = phases.length -1 ; i < len; i++) { // Skip ANY_PHASE placeholder
  2
  3             if (context.getRenderResponse() ||
  4                 context.getResponseComplete()) {
  5                 break;
  6             }
  7
  8             phases[i].doPhase(context, this, listeners.listIterator());
  9
10  }

在LifeCycle的render方法中,也會檢查FacesContext的responseComplete狀態,如果為true,那麼就不再執行render Phase。於是我們此刻知道了在我們自己所寫的一些代碼或者JSF庫裡面的一些代碼中,調用FacesContext的 responseComplete方法和renderResponse得作用原理。render方法主要代碼如下:

1 if (!context.getResponseComplete()) {
2       response.doPhase(context, this,listeners.listIterator());
3 }

另外注意,Phase這個概念、接口,以及幾個實現,都是jsf-ri項目中的,而在jsf-api中不存在Phase這個概念。所以,LifeCycle是JSF標准的內容,而通過幾個Phase來處理請求這種實現是sun的參考實現的做法。

最後,可以看到對於每一個phase都調用了doPhase方法,同時把LifeCycle和FacesContext當做參數傳入了。值得注意的是,所謂的phaseListener,也傳入了phase的doPhase方法中,由此大約能夠想明白這個“階段監聽器”的道理了。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved