動態代理在WEB與JDBC開發中的應用(WEB篇)

來源:互聯網
上載者:User

標籤:blog   http   io   使用   java   ar   檔案   資料   2014   

WEB案例

目前有一個2005年開始,基於Struts1的Web項目A,其驗證部分依賴於主站的SSO(單點登入)。在請求網站A的時候,使用者會被強制帶去做SSO驗證,通過身分識別驗證後後,主站會自動地把請求轉寄至A網站,並在request header中添加了用於儲存登入使用者ID的新屬性SM_USER,然後A網站根據使用者ID提供相應的服務。由於該項目是一個既存項目,所以其中殘餘大量像下面一樣的測試代碼。

String user_id = request.getHeader("XX_USER");if (user_id == null) {    user_id = "my_hard_coded_user_id";}UserProfile userProfile = new BizDao().getUserProfile(user_id);

其根本原因是在本地測試的時候無法於生產環境的SSO對接,只有把代碼提交至公用的DEV伺服器、UAT伺服器或PROD伺服器後,才能享受SSO為A站所提供的XX_USER資料,所以程式員在無法取得header資料的情況下,直接簡單粗暴地對本地環境進行了寫入程式碼處理。在只有幾個人的小團隊,這樣的處理可能看起來也無所謂,但長年下來經手的人數也相當可觀了,很多人都習慣使用自己的ID做測試,所以在SVN的曆史版本中,硬式編碼ID從A改到B、改到C、改到D……

問題分析

每個人都根據自己的喜好選擇了使用自己的ID或是他人的ID,那麼是否有一種辦法可以統一介面一勞永逸呢?可能最容易想到的就是HttpServletRequest.setHeader,可惜HttpServletRequest並沒有這樣的API,為啥?個人猜測可能是因為request源於用戶端,伺服器端應該保持請求的原始性、純淨性和無毒性吧,而HttpServletResponse(http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html)則是在應用程式的控制之下,所以程式員可以對其任意踐踏,setHeader、addHeader以及getHeader、getHeaders、getHeaderNames。既然沒有API可用,直接進行封裝代理吧,在Google的協助下我們可以找到現成的方案來對request中的header進行重新定製,重點是HttpServletRequestWrapper類的實現。

http://vangjee.wordpress.com/2009/02/25/how-to-modify-request-headers-in-a-j2ee-web-application/

其實這個方案是在我實現動態代理方案之後找到的,兩者思路幾乎是一樣的,都是對原始request進行封裝代理,重新實現getHeader方法。

解決方案

不廢話,直接上代碼!

private static class RequestInvocationHandler implements InvocationHandler {    private HttpServletRequest wrappedRequest;    public RequestInvocationHandler(HttpServletRequest r) {        wrappedRequest = r;    }    public static String dummyData = "my_hard_coded_id";    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        if ("getHeader".equals(method.getName()) && args.length == 1 && "SM_USER".equals(args[0])) {        return dummyData;        }        return method.invoke(wrappedRequest, args);    }    public static HttpServletRequest createRequestWapper(HttpServletRequest r) {    if (null != r.getParameter("u")) {    dummyData = r.getParameter("u");    }        return (HttpServletRequest)(Proxy.newProxyInstance(HttpServletRequest.class.getClassLoader(),            new Class[] {HttpServletRequest.class},                new RequestInvocationHandler(r)));    }}

上面代碼實現了對Request對象的代理,所有針對Request對象的調用都需經過invoke方法。在invoke方法中,我們可以針對不同的方法簽名進行更為細粒度的控制。比如在WEB案例中提到的問題,可以專門針對getHeader方法進行重新定製,本來Request Header中並無該資料,但我們可以硬生生地“造”出資料。另外除了可以“造”出測試資料外,還可以通過請求中攜帶的參數“u”動態地進行資料修改,這樣就實現了使用者切換的功能。

既然代理類的問題解決了,下面該談談應在何時何地植入代理對象了。何時何地可以理解為切入時機,其實最初的是在org.apache.struts.action.RequestProcessor中植入代理對象的,但是在使用過程中發現該實現有一個弊端,那就是在非Struts請求時無法使用代理對象,比如直接存取JSP檔案或是其它Servlet所提供的服務路徑。這時自然而然地想到Filter,而使用Filter也是一痛,加入一個全新的Filter吧,有點破壞的整體設計的感覺,而放入其它Filter之中的話,看起來又不倫不類。但好歹是測試用,這兩個方案可以折衷選擇其一,具體實現如下。

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletExceptionrequest = RequestInvocationHandler.createRequestWapper((HttpServletRequest)request);chain.doFilter(request, response);}

整體工作流程如下,使用者首先發出請求,然後request對象在filter中被替換成代理對象,替換後的request被傳入doFilter方法,之後不論是Servlet、Struts還是JSP,它們用到的都是我們定製的Request對象。

           +---------+         +---------+           |         |         |         | Request   |         | +-----> | Servlet |+--------> |  Filter |         |         |           | +----+  |         |  Struts |           | Request |         |         | Response  |      is |         |         |<--------+ | wrapped |         |         |           |    here | <-----+ |         |           |         |         |         |           +---------+         +---------+
後記

當然,如果想要修改request對象不止這一種方法,比如正統的方式是定義一個HttpServletRequestWrapper來重新定義request,具體案例請參考http://vangjee.wordpress.com/2009/02/25/how-to-modify-request-headers-in-a-j2ee-web-application/

動態代理在WEB與JDBC開發中的應用(WEB篇)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.