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

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

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

    OOPAA

    Focusing on OO, Patterns, Architecture, and Agile
    posts - 29, comments - 75, trackbacks - 0, articles - 0
      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

    play! framework hot swap 淺析

    Posted on 2008-12-30 17:06 mingj 閱讀(4503) 評(píng)論(12)  編輯  收藏 所屬分類: framework 框架
    play! 最大的賣點(diǎn)就在于 hot swap,正如它自己宣稱的:
    reach your maximum productivity。play! 允許開發(fā)人員修改java文件,保存,然后刷新瀏覽器,立馬可以看到效果。不需要編譯,也不需要重啟服務(wù)器。
    Java 要想實(shí)現(xiàn)動(dòng)態(tài)更新 class 文件,不外乎兩種手段:替換 classloader、替換 JVM。因?yàn)樘鎿Q JVM 引起的開銷更大,需要維護(hù) JVM 的堆、棧等運(yùn)行信息,所以 hot swap 通常是選擇替換 classloader。比如 grails 里面就是選擇替換 classloader,它會(huì)自己維護(hù)一個(gè)線程,定期輪詢?cè)次募欠癜l(fā)生修改,以替換原來的 classloader。那么 play! 宣稱的 hot swap 又是怎么實(shí)現(xiàn)的呢?
    讓我們來看看play! 的內(nèi)部流程:
    1. play! 使用了 Apache Mina 作為底層的 http server,然后使用了自己關(guān)于 Mina IoHandler 接口的實(shí)現(xiàn)—— HttpHandler
    2. 當(dāng)瀏覽器發(fā)起一個(gè) request:
    2.1 Mina Server 生成一個(gè) Mina Request,轉(zhuǎn)發(fā)給 HttpHandler 的 messageReceived 方法
    2.2 play! 解析 Mina Request 和 Mina Session,包裝成自己的 Request 對(duì)象

    Request request = parseRequest(minaRequest, session);

    2.3 play! 檢測(cè) Route 文件修改情況,根據(jù) Route 配置信息將 Route/Action 的信息賦給 Request 對(duì)象

    Router.detectChanges();
    Router.route(request);

    2.4 play! 根據(jù)當(dāng)前配置的開發(fā)模式來采用不同的策略調(diào)用 Action 來理 Request

    if (Play.mode == Play.Mode.DEV) {
    Invoker.invokeInThread(
    new MinaInvocation(session, minaRequest, minaResponse, request, response));
    }
    else {
    Invoker.invoke(
    new MinaInvocation(session, minaRequest, minaResponse, request, response));
    }

    2.5 如果 play! 當(dāng)前是 DEV 模式,invokeInThread方法會(huì)讓 invocation 對(duì)象代理 run() 方法

    public void run() {
    try {
    before();
    execute();
    after();
    }
    catch (Throwable e) {
    onException(e);
    }
    finally {
    _finally();
    }
    }

    咱們來看看 before() 方法:
    public static void before() {
    Thread.currentThread().setContextClassLoader(Play.classloader);
    if(!Play.id.equals("test")) {
    Play.detectChanges();
    if (!Play.started) {
    Play.start();
    }
    }
    //
    }

    在 Play 類的 detectChanges() 方法里面,有這么一句:
    classloader.detectChanges();

    哈哈,play! 修改源文件后,刷新瀏覽器即見效的奧秘就在這里了。再進(jìn)去看看 play! 自定義 classloader 的 detectChanges() 方法:

    public void detectChanges() {
    // Now check for file modification
    List<ApplicationClass> modifieds = new ArrayList<ApplicationClass>();
    for (ApplicationClass applicationClass : Play.classes.all()) {
    if (applicationClass.timestamp < applicationClass.javaFile.lastModified()) {
    applicationClass.refresh();
    modifieds.add(applicationClass);
    }
    }
    List
    <ClassDefinition> newDefinitions = new ArrayList<ClassDefinition>();
    Map
    <Class, Integer> annotationsHashes = new HashMap<Class, Integer>();
    for (ApplicationClass applicationClass : modifieds) {
    annotationsHashes.put(applicationClass.javaClass, computeAnnotationsHash(applicationClass.javaClass));
    if (applicationClass.compile() == null) {
    Play.classes.classes.remove(applicationClass.name);
    }
    else {
    applicationClass.enhance();
    BytecodeCache.cacheBytecode(applicationClass.enhancedByteCode, applicationClass.name, applicationClass.javaSource);
    newDefinitions.add(
    new ClassDefinition(applicationClass.javaClass, applicationClass.enhancedByteCode));
    }
    }
    try {
    HotswapAgent.reload(newDefinitions.toArray(
    new ClassDefinition[newDefinitions.size()]));
    }
    catch (ClassNotFoundException e) {
    throw new UnexpectedException(e);
    }
    catch (UnmodifiableClassException e) {
    throw new UnexpectedException(e);
    }
    // Check new annotations
    for (Class clazz : annotationsHashes.keySet()) {
    if (annotationsHashes.get(clazz) != computeAnnotationsHash(clazz)) {
    throw new RuntimeException("Annotations change !");
    }
    }
    // Now check if there is new classes or removed classes
    int hash = computePathHash();
    if (hash != this.pathHash) {
    // Remove class for deleted files !!
    for (ApplicationClass applicationClass : Play.classes.all()) {
    if (!applicationClass.javaFile.exists()) {
    Play.classes.classes.remove(applicationClass.name);
    }
    if(applicationClass.name.contains("$")) {
    Play.classes.classes.remove(applicationClass.name);
    }
    }
    throw new RuntimeException("Path has changed");
    }
    }

    HotswapAgent類的 reload 方法如下:
    public static void reload(ClassDefinition definitions) throws UnmodifiableClassException, ClassNotFoundException {
    instrumentation.redefineClasses(definitions);
    }

    讀到這里,也就弄清楚了 play! 怎么實(shí)現(xiàn) hot swap 的原理了,還是調(diào)用java.lang.instrument目錄下的類和方法來實(shí)現(xiàn)的 hot swap。不存在魔法,play! 還是選擇了替換 classloader,只不過這個(gè)替換動(dòng)作發(fā)生在處理 http request 的時(shí)候,于是開發(fā)人員用起來就是“刷新瀏覽器就可以看見效果了”。



    評(píng)論

    # re: play! framework hot swap 淺析  回復(fù)  更多評(píng)論   

    2008-12-30 19:09 by 綿陽人才網(wǎng)
    very good! 綿陽 的 人才 我 wite...

    # re: play! framework hot swap 淺析  回復(fù)  更多評(píng)論   

    2008-12-30 19:25 by 太陽里的雪
    play! 框架的controller和model分包,及view下的html文件目錄組織怎么搞?

    # re: play! framework hot swap 淺析  回復(fù)  更多評(píng)論   

    2008-12-30 20:16 by 太陽里的雪
    用了一下,某些方面比Grails還要強(qiáng)~~

    # re: play! framework hot swap 淺析  回復(fù)  更多評(píng)論   

    2008-12-30 20:28 by mingj
    @太陽里的雪
    你說文件目錄結(jié)構(gòu)怎么搞是什么意思?
    是說怎么放置相應(yīng)的文件么?

    你可以看看/resources目錄下的application-skel文件夾
    這下面就是新建application的skeleton

    # re: play! framework hot swap 淺析  回復(fù)  更多評(píng)論   

    2008-12-30 21:22 by 太陽里的雪
    就是我要把controller和model要分包,好象包名必須以controllers和models開頭才行。

    另外一個(gè)問題就是怎么跟spring結(jié)合。

    # re: play! framework hot swap 淺析  回復(fù)  更多評(píng)論   

    2008-12-30 22:55 by shinewang
    @太陽里的雪
    最新的stable4里面有個(gè)SpringPlugin

    # re: play! framework hot swap 淺析  回復(fù)  更多評(píng)論   

    2008-12-30 23:50 by mingj
    @太陽里的雪
    是的,這是play! 要求的convention
    被寫死在Play類里面了

    # re: play! framework hot swap 淺析  回復(fù)  更多評(píng)論   

    2008-12-31 02:03 by 太陽里的雪
    今天試用了一下,play!模版處理能力目前實(shí)在是太差啦~~功能太少~~

    # re: play! framework hot swap 淺析  回復(fù)  更多評(píng)論   

    2008-12-31 10:46 by mingj
    @太陽里的雪
    現(xiàn)階段的play! 的確只能算是個(gè)玩具
    一些編程理念和普遍接受的理念大相徑庭

    稍后我還會(huì)推出其他的博文來分析play!種種之痛的
    敬請(qǐng)期待:)

    # re: play! framework hot swap 淺析  回復(fù)  更多評(píng)論   

    2008-12-31 19:59 by 夢(mèng)想在這里起飛
    寫得不錯(cuò)啊,看看我這個(gè)
    開源的報(bào)表ireport項(xiàng)目web應(yīng)用
    http://ireport.cubebi.com


    # re: play! framework hot swap 淺析  回復(fù)  更多評(píng)論   

    2009-01-05 12:44 by ajf
    感興趣的朋友可以俺整地看看這個(gè)
    ajf agile java framework

    http://www.tkk7.com/ajf/archive/2009/01/03/249618.html

    # re: play! framework hot swap 淺析  回復(fù)  更多評(píng)論   

    2011-10-28 15:02 by 孫健
    @太陽里的雪
    可是擴(kuò)展及其方便 相比較JSP。

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 一级毛片免费一级直接观看| 免费乱码中文字幕网站| 国产精品福利在线观看免费不卡| 亚洲AV一二三区成人影片| 亚洲国产精品VA在线观看麻豆| 又粗又大又硬又爽的免费视频| 久久久久久精品免费看SSS| 韩日电影在线播放免费版| 亚洲AV第一成肉网| 亚洲国产成人久久综合一区| 亚洲AV无码成人精品区天堂| 亚洲Av无码乱码在线znlu| 四色在线精品免费观看| 无码国产精品一区二区免费 | 成年在线观看网站免费| 亚洲免费人成在线视频观看| 国产成人无码精品久久久久免费| 亚洲av日韩aⅴ无码色老头| 亚洲综合久久精品无码色欲| 亚洲精品国产情侣av在线| 久久久久久亚洲精品中文字幕| 亚洲一区二区三区免费| 亚洲AV无码成H人在线观看| 在线观看免费a∨网站| a级毛片无码免费真人| 18国产精品白浆在线观看免费 | 久久久久亚洲AV无码专区桃色| 国产国产成年年人免费看片| 免费看片免费播放| 成人免费无码大片A毛片抽搐色欲| 精品成在人线AV无码免费看| 在线观看免费av网站| 最近最新高清免费中文字幕 | 激情97综合亚洲色婷婷五| 亚洲福利视频一区二区| 亚洲高清成人一区二区三区 | 中文字幕无码毛片免费看| 成人自慰女黄网站免费大全| 中国性猛交xxxxx免费看| 在线观看免费视频一区| 久久久久国产精品免费看|