<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 23,comments - 66,trackbacks - 0
    by lostfire
    如果我們把一個JSP文件發布到Tomcat里邊,JSP是可以動態改變得,也就是說隨著這個JSP文件的改變,通過瀏覽器訪問,可以獲得不同的結果。然而有沒有想過能夠讓java代碼像jsp那樣動態的改變?
    實際上通過java的反射機制和內建的代理模式,完全可以做到這一點。下面就一步一步的說一下這是如何實現的。

    1,準備知識
    • 代理模式
    代理模式是一種對象的結構模式,簡單的說就是給某個對象提供一個代理對象,并通過代理對象來訪問真正的對象。
    按照《java與模式》里邊說說的,proxy其實有很多種用法:Remote proxy,Vitual Proxy,Copy-on-Write Proxy,Cache Proxy,Firewall proxy,Synchronization Proxy,Smart Reference Proxy等等。總體來說,都起到一個網絡中代理服務器的作用,只不過在代理中添加一些代碼實現不同的功能。
    代理模式的要點就是不直接訪問要訪問的對象,而是通過代理對象,因此就可以在調用實際對象前或調用后利用消息傳遞做一些額外的工作。
    • 反射機制與動態編譯
    java的反射機制是java被視為動態語言的重要特性,主要是通過java.lang.reflect包中提供的工具對于給定名稱的class,filed,method進行訪問。這種動態性給程序提供了很多的靈活性,本文要介紹的功能就得益于java的這一機制。
    動態編譯算是java反射的加強補充,在j2se 1.6以前的版本里邊是通過tools.jar中的com.sun.tools.javac包來提供的,在當前已經發布的j2se1.6 beta2中已經將動態編譯作為j2se的一部分了。
    要讓java代碼能夠像jsp那樣動態的使用,需要探測到java文件的改變,并動態編譯成class文件,再用ClassLoader將編譯好的class載入,因此這一部分是不可或缺的。
    • Java的內建代理
    j2se在1.3以后提供了Proxy、InvocationHandler來支持代理模式。
    對于java內建的代理來說,就是client不直接訪問對象,而是通過Proxy對象來訪問,而在訪問實際對象前后我們可以自己定義一些其他的操作。
    具體來講,client訪問的對象通過Proxy.newProxyInstance ()給出,client要訪問的實際的類可以通過Proxy.getProxyClass獲得,而實際的調用將訪問到我們實現的 InvocationHandler對象的invoke()方法中來。在invoke()方法中我們可以為實際的調用添加額外的代碼以滿足不同的需要。
    在我后邊講到的具體實現中就可以看到,我們正是在實現InvocationHandler的MyInvocationHandler的invoke()方法中來判斷java文件的改變,對于改變動態的編譯和裝載和調用來達到我們預期的目標的,java內建的代理模式可謂居功至尾。

    2,基本服務

    為了演示像jsp一樣的java的效果,讓我們來定義的一種服務。

    public interface Postman {
    ??? void deliverMessage(String msg);
    }
    具體的實現中,候選的有兩種方案:
    • 第一種是將輸出字符串到控制臺:
    public class PostmanImpl implements Postman {

    ??? private PrintStream output;
    ??? public PostmanImpl() {
    ??? ??? output = System.out;
    ??? }
    ???
    ??? public void deliverMessage(String msg) {
    ??? ??? output.println("[Postman] " + msg);
    ??? ??? output.flush();
    ??? }
    }
    • 第二種是輸出字符串到文本:
    public class PostmanImpl implements Postman {

    ??? private PrintStream output;
    ???
    ??? public PostmanImpl() throws IOException {
    ?? ??? output = new PrintStream(new FileOutputStream("msg.txt"));
    ??? }

    ??? public void deliverMessage(String msg) {
    ??? ??? output.println("[Postman] " + msg);
    ??? ??? output.flush();
    ??? }
    }
    在程序運行中,我們就是要通過動態修改PostmanImpl 來觀察這個JSP一樣的現象。

    3,訪問服務

    這里要介紹一些訪問服務的main程序,以便看到這種方式的優越性。

    public class PostmanApp {

    ??? public static void main(String[] args) throws Exception {
    ??? ??? BufferedReader sysin = new BufferedReader(new InputStreamReader(System.in));
    ??? ??? Postman postman = getPostman();
    ??? ??? while (true) {
    ??? ??? ??? System.out.print("Enter a message: ");
    ??? ??? ??? String msg = sysin.readLine();
    ??? ??? ??? postman.deliverMessage(msg);
    ??? ??? }
    ??? }

    ??? private static Postman getPostman() {
    ??? ??? DynaCode dynacode = new DynaCode();
    ??? ??? dynacode.addSourceDir(new File("dynacode"));
    ??? ??? return (Postman) dynacode.newProxyInstance(Postman.class,
    ??? ??? ??? ??? "sample.PostmanImpl");
    ??? }
    }
    我們可以看到獲取PostMan對象,只是在初始化的過程中做過一次,后邊只是訪問其deliverMessage()方法,而 sample.PostmanImpl這一實現的動態改變完全被掩藏在這個小小框架的后邊。Java文件改變后的編譯、重新載入、對象實例化和方法的調用過程完全不可見,是不是很神奇的實現。

    4,DynaCode

    看了這樣的主程序,你可能會首先看一下DynaCode的實現,然而我不準備詳細講述DynaCode的實現,盡管它的實現最為復雜。因為 DynaCode只是簡單的包裝了java.lang.reflect.Proxy,通過添加幾個處理class路徑和java路徑的方法輔助來完成工作的,我不想重點介紹java反射機制的,因此我們只來看DynaCode一個重要的方法。

    public Object newProxyInstance(Class interfaceClass, String implClassName)
    ??? ??? ??? throws RuntimeException {
    ??? ??? MyInvocationHandler handler = new MyInvocationHandler(
    ??? ??? ??? ??? implClassName);
    ??? ??? return Proxy.newProxyInstance(interfaceClass.getClassLoader(),
    ??? ??? ??? ??? new Class[] { interfaceClass }, handler);
    }
    好了,看到了吧,DynaCode只是在內部做了一個InvocationHandler實現,并簡單的使用了Proxy的newProxyInstance()方法。

    5,InvocationHandler實現

    根據上面提到的java的內建代理模式,要實現一個InvocationHandler,下面這段代碼展示了MyInvocationHandler 的主要部分:

    private class MyInvocationHandler implements InvocationHandler {
    ??? ??? String backendClassName;//實際的類名
    ??? ??? Object backend;//實際的類對象
    ??? ??? public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    ??? ??? ??? /**
    ? ? ? ? ? ? ? *? 在第一載入的時候通過loadClass來載入所需要的服務實現對象,后邊每次檢查java文件是否被修改過,
    ????????????? *? 如果被修改就unload當前的對象,編譯并重新載入該類。
    ????????????? */
    ??? ??? ??? Class clz = loadClass(backendClassName);
    ??? ??? ??? if (backend.getClass() != clz) {
    ??? ??? ??? ??? backend = newDynaCodeInstance(clz);
    ??? ??? ??? }

    ??? ??? ??? // 調用有效的對象的方法
    ??? ??? ??? return method.invoke(backend, args);
    ??? ??? }
    ??? }
    在MyInvocationHandler中保存了實現接口的類名和該類的一個對象,該對象也就是通過newDynaCodeInstance()方法得到的對象。在每一次調用該對象的方法的時候,java的Proxy機制保證了系統會自動調用MyInvocationHandler的invoke方法。
    這里采用反射進行動態載入的程序,調用的實際工作是在InvocationHandler的invoke方法中做的,因此InvocationHandler要保存實際的對象。
    代理模式的好處是從使用者看來如同調用實際的對象是一樣的,而實際上可以通過代理對象,程序可以動態采用不同的接口實現來完成工作,這一過程只需要在Proxy.newProxyInstance()中給定不同的實現類即可。

    本文主要參照Add dynamic Java code to your application (by LiYang),完整的代碼可以從這里下載
    posted on 2006-06-28 23:28 rd2pm 閱讀(3178) 評論(0)  編輯  收藏 所屬分類: java language

    主站蜘蛛池模板: 国产精品福利片免费看| 国产精品亚洲专区在线观看| 精品久久久久久久久亚洲偷窥女厕| 2020因为爱你带字幕免费观看全集 | 久久亚洲精品AB无码播放| 一级做a爰性色毛片免费| 亚洲AV无码乱码在线观看牲色| 久久无码av亚洲精品色午夜| 暖暖在线日本免费中文| 国产亚洲视频在线观看网址| 免费a级毛片无码av| 一级做a爰性色毛片免费| 伊人亚洲综合青草青草久热| a级黄色毛片免费播放视频| 亚洲精品无码永久在线观看你懂的 | 免费不卡在线观看AV| 国产精品亚洲综合一区| 羞羞视频免费网站在线看| 国产日韩亚洲大尺度高清| 日韩内射激情视频在线播放免费| 亚洲自偷精品视频自拍| 免费H网站在线观看的| 亚洲日韩中文字幕一区| 国产jizzjizz视频全部免费| 免费国产高清毛不卡片基地| 亚洲人成图片小说网站| h视频在线观看免费网站| 亚洲精品无码成人| 久久久久亚洲AV成人网| 99精品免费观看| 亚洲愉拍一区二区三区| 免费在线观看a级毛片| 成人电影在线免费观看| 中文字幕亚洲综合小综合在线| 国产无遮挡吃胸膜奶免费看| 久久一区二区免费播放| 亚洲美女视频免费| 免费一级国产生活片| 最近免费中文字幕mv电影| 国产亚洲欧美在线观看| 亚洲视频免费在线观看|