<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
    如果我們把一個(gè)JSP文件發(fā)布到Tomcat里邊,JSP是可以動(dòng)態(tài)改變得,也就是說(shuō)隨著這個(gè)JSP文件的改變,通過(guò)瀏覽器訪問(wèn),可以獲得不同的結(jié)果。然而有沒(méi)有想過(guò)能夠讓java代碼像jsp那樣動(dòng)態(tài)的改變?
    實(shí)際上通過(guò)java的反射機(jī)制和內(nèi)建的代理模式,完全可以做到這一點(diǎn)。下面就一步一步的說(shuō)一下這是如何實(shí)現(xiàn)的。

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

    2,基本服務(wù)

    為了演示像jsp一樣的java的效果,讓我們來(lái)定義的一種服務(wù)。

    public interface Postman {
    ??? void deliverMessage(String msg);
    }
    具體的實(shí)現(xiàn)中,候選的有兩種方案:
    • 第一種是將輸出字符串到控制臺(tái):
    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();
    ??? }
    }
    在程序運(yùn)行中,我們就是要通過(guò)動(dòng)態(tài)修改PostmanImpl 來(lái)觀察這個(gè)JSP一樣的現(xiàn)象。

    3,訪問(wèn)服務(wù)

    這里要介紹一些訪問(wèn)服務(wù)的main程序,以便看到這種方式的優(yōu)越性。

    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對(duì)象,只是在初始化的過(guò)程中做過(guò)一次,后邊只是訪問(wèn)其deliverMessage()方法,而 sample.PostmanImpl這一實(shí)現(xiàn)的動(dòng)態(tài)改變完全被掩藏在這個(gè)小小框架的后邊。Java文件改變后的編譯、重新載入、對(duì)象實(shí)例化和方法的調(diào)用過(guò)程完全不可見(jiàn),是不是很神奇的實(shí)現(xiàn)。

    4,DynaCode

    看了這樣的主程序,你可能會(huì)首先看一下DynaCode的實(shí)現(xiàn),然而我不準(zhǔn)備詳細(xì)講述DynaCode的實(shí)現(xiàn),盡管它的實(shí)現(xiàn)最為復(fù)雜。因?yàn)?DynaCode只是簡(jiǎn)單的包裝了java.lang.reflect.Proxy,通過(guò)添加幾個(gè)處理class路徑和java路徑的方法輔助來(lái)完成工作的,我不想重點(diǎn)介紹java反射機(jī)制的,因此我們只來(lái)看DynaCode一個(gè)重要的方法。

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

    5,InvocationHandler實(shí)現(xiàn)

    根據(jù)上面提到的java的內(nèi)建代理模式,要實(shí)現(xiàn)一個(gè)InvocationHandler,下面這段代碼展示了MyInvocationHandler 的主要部分:

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

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

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

    主站蜘蛛池模板: 国产成人精品日本亚洲专区6| 亚洲精品二区国产综合野狼| 亚洲视频一区在线播放| a级片免费在线播放| 久久青青草原亚洲av无码| 性生大片视频免费观看一级| 又爽又高潮的BB视频免费看| 高潮毛片无遮挡高清免费视频| 国产精品久久香蕉免费播放| 亚洲AV色欲色欲WWW| 国产男女性潮高清免费网站| 国产精品亚洲av色欲三区| 免费看美女让人桶尿口| WWW亚洲色大成网络.COM| 日本一道一区二区免费看| 伊人久久国产免费观看视频| 亚洲偷自拍拍综合网| a毛片视频免费观看影院| 五月天网站亚洲小说| 精品无码免费专区毛片| 亚洲中文久久精品无码1| 色吊丝永久在线观看最新免费| 老司机亚洲精品影院在线观看| 亚洲成A人片77777国产| 中文字幕乱理片免费完整的| 亚洲天堂中文字幕| 成年女人免费视频播放体验区| 午夜亚洲WWW湿好爽| 亚洲中文字幕在线观看| 国产精品免费网站| 亚洲AV日韩综合一区| 亚洲一区二区三区国产精品| 三年片在线观看免费观看大全一| 亚洲妓女综合网99| 又黄又爽一线毛片免费观看| 免费久久人人爽人人爽av| 波多野结衣亚洲一级| 亚洲午夜精品久久久久久浪潮| 6080午夜一级毛片免费看6080夜福利 | 91大神在线免费观看| 亚洲AV无码国产一区二区三区|