beauty_beast

          上善若水 厚德載物

          學習設計模式之proxy模式

          Posted on 2005-08-19 16:58 柳隨風 閱讀(938) 評論(0)  編輯  收藏 所屬分類: java基礎

          前言: 本文只是本人的學習總結,目的希望能和大家一起交流分享,順便備忘,如有不正確的地方,歡迎指正。本文可能需要你對webwork框架有一定的了解。

           

          我們在開發中Proxy模式是經常用到的,代理主要用來對訪問的資源進行權限控制以及監控的目的,如果我們在開發系統需要對訪問的對象進行控制和監控的話,proxy模式是很有用途的。

          舉些例子:

          我們開發一個應用系統時,用戶請求任何頁面都要經過權限控制,最早開發的時候我們常常封裝一個權限驗證方法,然后在每個jsp或者對應的servlet中增加相關代碼,但是用戶對權限的需求往往是多變的,這樣一旦權限驗證方法變化(參數變化,增加方法),如果開發的系統很龐大的話,有可能你就需要修改幾百個jsp頁面或者servlet代碼。

          還有我們常需要判斷session是否過期,如果過期就要重新登陸系統,如果每個頁面或者servlet都要加判斷代碼,那也是件比較痛苦的事情。

          如果我們采用代理模式,增加Proxy對象,每次用戶請求必須通過proxy對象處理,由它專門處理相關權限控制,一旦權限需求變化了,只需要修改Proxy對象相關的實現方法。

          Proxy模式不僅僅用于上述場景,還可以在其他方面應用。

           

          我們可以研究研究webwork的源代碼,看看它是如何設計的。

           

          webwork開發框架目前是比較流行的web開發框架之一,最近我的開發項目就采用了該框架,它相比struts有很多優點(晚出來的再沒優點也不行啊,呵呵,關于其缺點也有,有時間再說),

          主要如下:

          1、    易單元測試;

          2、    線程安全;

          3、    允許使用截取器模塊化前/后處理. 攔截器可以通過配置動態添加, 兩者之間沒有任何耦合;

          4、    WebWork 2使用Ognl, 強大的表達式語言, 也可以訪問值棧. Ognl對集合和索引屬性的支持非常強大。

          其中優點3的實現和proxy模式是非常相關的,下面就講講webwork如何采用Proxy模式實現其優點3的。

           

          首先我們看看webwork的核心類ServletDispatcher的請求處理代碼:

          public void serviceAction(
          HttpServletRequest request, HttpServletResponse response, 
          String 
          namespace, String actionName, 
          Map requestMap, Map parameterMap, 
          Map sessionMap, Map applicationMap) 
          {
          HashMap extraContext 
          = createContextMap(requestMap, parameterMap, sessionMap, applicationMap, request, response, getServletConfig());
          extraContext.put(SERVLET_DISPATCHER, 
          this);
          try {
              ActionProxy proxy 
          =   ActionProxyFactory.getFactory).
          createActionProxy(
          namespace, actionName, extraContext);
             request.setAttribute(
          "webwork.valueStack", proxy.getInvocation().getStack());
             proxy.execute();
          }

          catch (ConfigurationException e) {
             log.error(
          "Could not find action", e);
             sendError(request, response, HttpServletResponse.SC_NOT_FOUND, e);
                 }

          catch (Exception e) {
             log.error(
          "Could not execute action", e);
             sendError(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR,e);
          }

          }


          .可以看到整個對請求的處理非常簡練:通過工廠方法獲取一個ActionProxy 實例,執行ActionProxy實例的execute()方法,所有請求都需要通過該方法處理。

          ActionProxyFactory.getFactory().createActionProxy(namespace, actionName, extraContext);

          這段代碼調用過程我簡單描述一下:

              首先ActionProxyFactory.getFactory().獲取到一個DefaultActionProxyFactory實例,然后該工廠實例調用createActionProxy(相關參數)方法創建一個DefaultActionProxy示例。
           

          下面我們看看這個DefaultActionProxy究竟是如何處理的:

          首先它會根據相關信息獲取當前Action配置對象,從中可以知道當前Action中配置了那些攔截器、Result等等配置信息,具體可以查看ActionConfig對象,然后創建一個調用對象DefaultActionInvocation實例(也是通過工廠方法),該實例調用invoke()方法完成該action配置的攔截器的攔截方法以及actionexecute()方法或action自定義的method的執行。

          public String invoke() throws Exception {
                  
          if (executed) {
                      
          throw new IllegalStateException("Action has already executed");
                  }

                  
          if (interceptors.hasNext()) {
                      Interceptor interceptor 
          = (Interceptor) interceptors.next();
                      resultCode 
          = interceptor.intercept(this);
                  }
           else {
                      
          if (proxy.getConfig().getMethodName() == null{
                          resultCode 
          = getAction().execute();
                      }
           else {
                          resultCode 
          = invokeAction(getAction(), proxy.getConfig());
                      }

                  }

                  
          // this is needed because the result will be executed, then control will return to the Interceptor, which will
                  
          // return above and flow through again
                  if (!executed) {
                      
          if (preResultListeners != null{
                          
          for (Iterator iterator = preResultListeners.iterator();
                                  iterator.hasNext();) 
          {
                              PreResultListener listener 
          = (PreResultListener) iterator.next();
                              listener.beforeResult(
          this, resultCode);
                          }

                      }


                      
          // now execute the result, if we're supposed to
                      if (proxy.getExecuteResult()) {
                          executeResult();
                      }

                      executed 
          = true;
                  }

                  
          return resultCode;
              }

          而一般攔截器對象都是AroundInterceptor的子類,在AroundInterceptor類中的攔截方法如下:

             public String intercept(ActionInvocation invocation) throws Exception {
                  String result 
          = null;
                  before(invocation);
                  result 
          = invocation.invoke();
                  after(invocation, result);
                  
          return result;
              }

           

          注意該調用對象的invoke方法比較有意思,它采用的是遍歷調用的方式,每個Action一般都有多個攔截器,每個攔截器執行完畢后再回調該調用對象的invoke方法,有點像鏈式,如果中間有自定義攔截器有發現異常,不要再執行下去,直接返回Result相關字符串,中斷之后的攔截器以及Action不再執行,正常情況下鏈尾是調用對應Action實例的execute()方法,獲取Result相關字符串后,根據字符串值獲取相關Result實例,執行Result實例中excute()方法派發或者重導向到相關視圖(jspvm等等),一旦鏈尾處理過請求后,鏈中的其他節點就不需要再派發。只需繼續執行攔截器中的after()方法(如果有的話)的執行,webwork采用這樣的方式實現主要是為了滿足action后處理功能的需要(有點跑題了,變成webwork框架源碼分析)

          題外話:從整個調用過程我們可以發現: Webwork框架的核心功能實際上都是在Xwork框架中實現的,Webwork實際上只是XworkB/S系統上的應用。

           

          結束總結:

          1、我們在開發時,如果要對訪問的對象進行統一預處理、控制、監控管理時可以采用Proxy模式。

          2Proxy模式往往和Factory模式一起使用。個人理解是因為考慮系統的擴展性、通用性,有可能有不同的類型的Proxy以及調用,根據不同的應用場景,可以采用不同的工廠創建。

          3、如果運用的不是很恰當的話,會造成Proxy的實現很龐大,并且和相關對象耦合過高,而webwork采用配置每個action對應的攔截器這種設計就非常好,耦合也比較低,實際上它變相的實現了每個對象采用不同的Proxy,個人感覺其這方面的設計很不錯,可以借鑒。





          主站蜘蛛池模板: 彩票| 中江县| 阜城县| 双流县| 双鸭山市| 长子县| 萨迦县| 长岭县| 泗水县| 温泉县| 双辽市| 江门市| 大荔县| 闻喜县| 临汾市| 伊春市| 尤溪县| 上高县| 南丹县| 华亭县| 泾阳县| 荔浦县| 广西| 奇台县| 炉霍县| 四川省| 双峰县| 怀宁县| 南皮县| 三台县| 苏尼特左旗| 浦城县| 乐都县| 象山县| 科尔| 上饶市| 鄢陵县| 山阳县| 吴忠市| 镇原县| 保亭|