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

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

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

    John Jiang

    a cup of Java, cheers!
    https://github.com/johnshajiang/blog

       :: 首頁 ::  :: 聯系 :: 聚合  :: 管理 ::
      131 隨筆 :: 1 文章 :: 530 評論 :: 0 Trackbacks
    你所不知道的五件事情--JAR文件
    這是Ted Neward在IBM developerWorks5 things系列文章中的一篇,講述了關于JAR的一些應用竅門,值得大家學習。(2010.06.27最后更新)

    摘要:許多Java開發者從沒有深入思考過JAR--他們只是在將類傳到產品服務器之前使用JAR打包這些文件罷了。但JAR并不僅僅是一個被重命名的 ZIP文件。學習如何使用Java歸檔文件的全部能力,包括打包Spring依賴和配置文件的小竅門。

        對大多數Java開發者而言,JAR與它的兄弟們,WAR和EAR,都是一長串Ant或Maven處理后的最終結果。一個標準的過程是將JAR復制到服務器的適應位置(或者,更少見地,復制到用戶的機器上),然后就把它遺忘了。
        準確地說,JAR能做的遠不止存儲源代碼,但你必須要知道它能做的其它事情,以及怎樣去使用它。在本"5 things"系列的分期文章中所介紹的竅門將展示如何制作大部分的Java歸檔文件(在有些例子中,也會涉及WAR和EAR),特別是在開發時期。
        因為有眾多的Java開發者在使用Spring(也因為Spring框架展示了一些相對于我們對JAR傳統應用的挑戰),其中若干竅門是特別針對Spring應用中的JAR文件。
        我將以一個標準的Java歸檔文件處理的例子開始,該例是下面各竅門的基礎。

    置于JAR中
        一般地,在編譯源代碼之后你會制作一個JAR文件,通過jar命令工具,或更為通用的Ant的jar工作,去把Java代碼(已經被包分隔開)歸集到單個文件中。這種處理很明了,在此處我就不作展示了,但在本文的后面我將回到JAR文件是如何被構造的這個主題中來。現在,我們只需打包Hello類,這是一個獨立運行的控制臺工具應用,該應用會向控制臺打印一條信息,這無疑是很有用的任務,如清單1所示:

    清單1. 用于打包的控制臺工具
    package com.tedneward.jars;

    public class Hello
    {
        
    public static void main(String[] args)
        {
            System.out.println(
    "Howdy!");
        }
    }

    Hello工具并不復雜,但以可執行程序開始,它是探索JAR文件的一個有用的輔助手段。

    1. JAR是可執行的
        像.NET和C++這樣的編程語言,在歷史上有操作系統友好方面優勢,只需在命令行中引入它們的名字(helloWorld.exe)或在GUI Shell中雙擊它們的圖標就會啟動這些應用。然而在Java編程中,啟動器程序--java--引導JVM運行,而后我們必須傳入一個命令行參數 (com.tedneward.Hello)用于指定將要啟動的含有main()方法的類。
        這些額外的步驟使得很難為Java創建用戶友好的應用。不僅僅是由于最終用戶必須在命令行中鍵入所有的這些元素(很多用戶都想避免這種情況),而且他或她會由于某種原因打錯字并得到一個晦澀的錯誤返回。
        解決方案就是使JAR文件"可執行",以便在執行JAR文件時,能讓Java啟動器自動地知道啟動哪個類。我們所需要做的只是在JAR文件的manifest(JAR文件META-INF中的MENIFEST.MF文件)中引入一個屬性,例如:

    清單2. 顯示入口點
    Main-Class: com.tedneward.jars.Hello

    manifest就是一組名值對。因為mainfest有時候對回車和空格比較敏感,所以在制作JAR時使用Ant去生成該文件要方便些。在清單3中,我就在Ant的jar任務中使用了manifest元素去指定要生成的manifest:

    清單3. 構建入口點
    <target name="jar" depends="build">
        
    <jar destfile="outapp.jar" basedir="classes">
            
    <manifest>
                
    <attribute name="Main-Class" value="com.tedneward.jars.Hello" />
            
    </manifest>
        
    </jar>
    </target>

    現在為了執行JAR文件,用戶所需要做的只是在命令行中指定文件名,通過命令java -jar outapp.jar。對于這種情況,在有些GUI Shell中雙擊JAR文件也是可以的。

    2. JAR能夠包含依賴信息

        Hello工具類的文字似乎已經擴展了,這樣對不同的實現的需求就變得很緊急了。像Spring或Guice這樣的依賴注入(DI)容器為我們處理了許多細節,但仍有一點兒障礙:

    清單4. Hello, Spring world!

    package com.tedneward.jars;

    import org.springframework.context.*;
    import org.springframework.context.support.*;

    public class Hello
    {
        
    public static void main(String[] args)
        {
            ApplicationContext appContext 
    =
                
    new FileSystemXmlApplicationContext("./app.xml");
            ISpeak speaker 
    = (ISpeak) appContext.getBean("speaker");
            System.out.println(speaker.sayHello());
        }
    }

    因為啟動器的-jar選項會被命令行中的-classpath選項所覆蓋,那么當你運行上述程序時,Spring需要出現在CLASSPATH中,并且要在環境變量中。幸運地是,JAR允許針對其它JAR依賴的聲明出現在manfiest中,這就隱式地創建了CLASSPATH而不需要你去聲明,如清單5 所示:

    清單5. Hello, Spring CLASSPATH!
    <target name="jar" depends="build">
        
    <jar destfile="outapp.jar" basedir="classes">
            
    <manifest>
                
    <attribute name="Main-Class" value="com.tedneward.jars.Hello" />
                
    <attribute name="Class-Path"
                        value
    ="./lib/org.springframework.context-3.0.1.RELEASE-A.jar
                            ./lib/org.springframework.core-3.0.1.RELEASE-A.jar
                            ./lib/org.springframework.asm-3.0.1.RELEASE-A.jar
                            ./lib/org.springframework.beans-3.0.1.RELEASE-A.jar
                            ./lib/org.springframework.expression-3.0.1.RELEASE-A.jar
                            ./lib/commons-logging-1.0.4.jar"
     />
                
    </manifest>
        
    </jar>
    </target>

    注意到Class-Path屬性包含有該應用的依賴相對于JAR的引用路徑。你也可以寫絕對引用路徑,或者完全不需要前綴,在這種情況下就要假設這些依賴 JAR文件與應用程序的JAR文件在同一目錄下。
        不幸地是,Ant的Class-Path屬性對應的value屬性必須出現在一行中,因為JAR manfiest無法應對多個Class-Path屬性,所以,所有的依賴必須出現在manifest文件的同一行中。可以肯定的是,這種做法很丑陋,但為了能使用命令java -jar outapp.jar,這是值得的。

    3. 可隱式地引用JAR
    如果你有多個不同的命令行工具(或其它的應用)需要使用Spring框架的JAR文件,那么將這些Spring JAR文件置于公共路徑中,以便所有的工具類都能被引用到。這樣做就能避免文件系統中滿是JAR文件的多份拷貝。Java運行時環境的公共JAR文件路徑,即大家所知的"擴展目錄",默認是位于JRE安裝路徑下的lib/ext子目錄中。
    JRE是一個可定制的路徑,但仍然很少在一個給定的Java環境中定制該路徑使我們能夠安全放心地假設lib/ext是一個存放JAR文件的安全地方,該目錄中的JAR文件將默認出現在Java運行時環境的CLASSPATH中。

    4. Java 6允許類路通配符

        作為一種避免龐大CLASSPATH環境變量(Java開發者在多年前就已經拋棄它了)和/或命令行-classpath參數的努力,Java 6引入了類路徑通配符選項。與在啟動時必須在一個參數中顯示地列出每個JAR文件不同,類路徑通配符允許你通過lib/*來指定該目錄下的所有JAR文件 (但不允許遞歸其子目錄中的JAR文件)設置到類路徑中。
        不幸地是,類路徑通配符并不能支持之前討論過的Class-Path屬性manifest條目。為了某些開發者任務,例如代碼生成或分析工具,使用類路徑通配符可以更方便地啟動Java應用程序(包括服務器)。

    5. JAR不只是包含代碼

        就像Java生態系統中的許多組成部分那樣,Spring依賴一個配置文件,該文件描述了如何去構建運行環境。如前所述,Spring依賴app.xml 文件,該文件與JAR文件存在于同一個目錄下--但經常地,開發者們會忘記復制JAR文件邊上的配置文件。
        sysadmin會編輯某些配置文件,但也有大量的配置文件(如Hibernate映射文件)在sysadmin的域之外,這將導致發布錯誤。一種明智的解決方案就是將代碼與配置文件打包在一起--這是可行的,因為JAR本質上就是改頭換面的ZIP。只需將配置文件包含在Ant任務中,或使用jar命令去構建JAR文件。
        不僅僅是配置文件,JAR還可以包含其它類型的文件。例如,如果我的SpeakEnglish組件想到訪問一個屬性文件,那么我會像清單6那樣進行設置:

    清單6. 隨機響應
    package com.tedneward.jars;

    import java.util.*;

    public class SpeakEnglish
        
    implements ISpeak
    {
        Properties responses 
    = new Properties();
        Random random 
    = new Random();

        
    public String sayHello()
        {
            
    // Pick a response at random
            int which = random.nextInt(5);
            
            
    return responses.getProperty("response." + which);
        }
    }

    將responses.properties置入JAR文件就意味著,不需要操心有太多文件要隨JAR文件一同部署了。要做到這些,只需在制作JAR的過程中包含上responses.properties文件。
    一旦你在JAR中存放了配置文件,你就可能就想著如何得到它。如果你所想要的數據位于同一JAR文件中,可以讓類的ClassLoader將該文件作為 JAR文件中的"資源"進行查找,使用ClassLoader的getResourceAsStream()方法,如清單7所示:

    清單7. ClassLoader定位資源
    package com.tedneward.jars;

    import java.util.*;

    public class SpeakEnglish
        
    implements ISpeak
    {
        Properties responses 
    = new Properties();
        
    // 

        
    public SpeakEnglish()
        {
            
    try
            {
                ClassLoader myCL 
    = SpeakEnglish.class.getClassLoader();
                responses.load(
                    myCL.getResourceAsStream(
                        
    "com/tedneward/jars/responses.properties"));
            }
            
    catch (Exception x)
            {
                x.printStackTrace();
            }
        }
        
        
    // 
    }

    你能使用這種操作找到任何類型的資源:配置文件,音頻文件,圖形文件,以及你所命名的其它文件。事實上,任何文件類型都可以綁定到JAR文件中,并通過 InputStream可再獲得該文件(使用ClassLoader類),然后就可以任何符合你喜好的方式來使用它們了。

    結論
        本文涵蓋了關于JAR的多數Java開發者最不知道的5件事情--至少基于歷史和軼事證據可以這么認為。注意,所有這些與JAR相關的竅門也同樣適用于 WAR。有些竅門(特別是Class-Path和Main-Class屬性)對于WAR不完全正確,因為Servlet環境會獲取目錄中的全部內容并有一個預定義的入口點。但綜合來看,這些竅門還是讓我們超越了這樣一種范式:"好吧,讓我們開始復制目錄下的所有文件吧..."。除了這些,他們還使得部署 Java應用變得非常容易。
        本系列的下一往篇文章是:你所不知道的五件事情--Java應用的性能監控。

    posted on 2010-06-27 18:01 John Jiang 閱讀(3111) 評論(8)  編輯  收藏 所屬分類: JavaSEJava翻譯

    評論

    # re: 你所不知道的五件事情--JAR文件(譯) 2010-06-27 19:05 何楊
    不錯!  回復  更多評論
      

    # re: 你所不知道的五件事情--JAR文件(譯)[未登錄] 2010-06-27 20:32 feenn
    文章很好,JAR不只是包含代碼——其實還可以包含動態鏈接庫(比如SWT)、壓縮包甚至是jar本身  回復  更多評論
      

    # re: 你所不知道的五件事情--JAR文件(譯) 2010-06-28 09:43 隔葉黃鶯
    還好,我還都知道這五件事情。  回復  更多評論
      

    # re: 你所不知道的五件事情--JAR文件(譯) 2010-06-28 10:35 Sha Jiang
    > 還好,我還都知道這五件事情
    嗯,這幾點東西還算是常識。  回復  更多評論
      

    # re: 你所不知道的五件事情--JAR文件(譯) 2010-06-29 21:37 balckbat
    jar 里的配置文件可寫入嗎?  回復  更多評論
      

    # re: 你所不知道的五件事情--JAR文件(譯) 2010-06-29 22:46 Sha Jiang
    > jar 里的配置文件可寫入嗎?
    可以試試java.util.jar中的API...我沒有試過  回復  更多評論
      

    # re: 你所不知道的五件事情--JAR文件(譯) 2010-07-08 13:59 上鬼子當了
    我以為人人都知道呢?原來好多人都不知道啊。驚嘆!
    怪不得很多程序員抱怨自己工資低。。。  回復  更多評論
      

    # re: 你所不知道的五件事情--JAR文件(譯) 2010-07-08 19:12 Sha Jiang
    > 我以為人人都知道呢?原來好多人都不知道啊。驚嘆!
    也不必驚嘆...在現實世界中,任何常識,總會有人不知道

    > 怪不得很多程序員抱怨自己工資低。。。
    。。。  回復  更多評論
      

    主站蜘蛛池模板: 久久精品国产亚洲av麻豆小说| 国产成人精品日本亚洲18图| 日韩免费无码一区二区三区| 亚洲成人黄色在线观看| 巨胸喷奶水视频www网免费| 免费看一级一级人妻片| 亚洲男人第一av网站| 午夜两性色视频免费网站| 国产乱妇高清无乱码免费| 亚洲一级黄色大片| 中文字幕亚洲电影| 免费毛片a在线观看67194| 最好2018中文免费视频| 亚洲成a人片在线观| 亚洲人成无码网站久久99热国产| **真实毛片免费观看| 一级毛片免费播放男男| 国产成人精品日本亚洲网址| 国产精一品亚洲二区在线播放| 大学生美女毛片免费视频| 日韩电影免费在线观看中文字幕 | 亚洲色无码国产精品网站可下载| 国产亚洲精品拍拍拍拍拍| 成人毛片免费在线观看| 99ee6热久久免费精品6| 一级一片免费视频播放| 亚洲日韩精品无码专区加勒比☆| 亚洲国产精品免费视频| 久久久久亚洲AV无码专区网站| 啦啦啦在线免费视频| 日本高清在线免费| 日本免费中文字幕| 国产成人无码精品久久久久免费 | 成全动漫视频在线观看免费高清版下载 | 99亚洲男女激情在线观看| 亚洲另类自拍丝袜第1页| 亚洲国产成人一区二区三区| 亚洲国产成人影院播放| 免费看大黄高清网站视频在线| 色老头永久免费网站| 99热在线免费播放|