Java Jar : sealed in manifest

來源:互聯網
上載者:User

標籤:

在上一篇文章中說到了Manifest.mf檔案中可以通過Sealed屬性來指定某些包是否是密封的。那麼到底什麼是密封的,如何來理解它呢?

 

對於sealed,官方文檔中的說法如下:

    JAR files and packages can be optionally sealed so that an package can enforce consistency within a version.    A package sealed within a JAR specifies that all classes defined in that package must originate from the same JAR. Otherwise, a SecurityException is thrown.    如果一個package通過JAR檔案清單指定了sealed,那麼這個包下的所有的類都必須是出自同一個jar檔案。不然的話,就出拋出一個SecurityException。

 

為瞭解決這個疑惑,來做幾個測試吧,通過測試來瞭解sealed:

 

1:在一個package中隨便寫上兩個類:ClassA、ClassB:

 

在com.fjn.java.util包下有:

 

 

ClassA:

package com.fjn.java.util.jar;/** *  * @author [email protected] 2015年7月10日 * */public class ClassA {    String id = "100";    String name = "hello";    public void showInfo() {        System.out.println(this);    }    @Override    public String toString() {        return "id: " + this.id + ", name: " + this.name;    }}

  

ClassB:

package com.fjn.java.util.jar;/** *  * @author [email protected] 2015年7月10日 * */public class ClassB {    public static void main(String[] args) {        ClassA obj=new ClassA();        obj.name="hello ,java sealed";        obj.showInfo();    }}

 

2:打包並設定不sealed 

 

現在打包成兩個包(打包時,都設定不sealed):

1)只將ClassA打進包中,打包為java_sealed_v1.jar

2)將com.fjn.java.util整體打包,名字是:java_sealed_v2.jar

 

java_sealed_v1.jar的清單:

Manifest-Version: 1.0Name: com/fjn/java/util/jar/Sealed: fasle

 

java_sealed_v2.jar的清單: 

Manifest-Version: 1.0Sealed: false

第3步:寫測試案例 

建立一個新的project,匯入這兩個jar。測試類別如下:

package com.java.sealtest;import com.fjn.java.util.jar.ClassA;import com.fjn.java.util.jar.ClassB;public class SealedTest {        public static void main(String[] args) {        ClassA objA=new ClassA();        System.out.println(objA);        System.out.println(Package.getPackage("com.fjn.java.util.jar").isSealed());        System.out.println(objA.getClass().getProtectionDomain().getCodeSource().getLocation());        ClassB objB=new ClassB();        System.out.println(objB);        System.out.println(Package.getPackage("com.fjn.java.util.jar").isSealed());        System.out.println(objB.getClass().getProtectionDomain().getCodeSource().getLocation());        ClassB.main(new String[0]);    }}

 


4步:進行測試 

 

測試1)都不使用sealed

執行上述測試案例,結果如下:

id: 100, name: hellofalsefile:/E:/workspace/Test/lib/java_sealed_v1.jar[email protected]falsefile:/E:/workspace/Test/lib/java_sealed_v2.jarid: 100, name: hello ,java sealed

 

該測試執行成功,從結果中可以看出,在ClassA 類是從java_sealed_v1.jar中載入的、ClassB是從java_sealed_v2.jar中載入的。 

  

 

測試2)java_sealed_v1.jar中的sealed啟用。

將java_sealed_v1.jar manifest.mf中的sealed設定為true,此時:

 

java_sealed_v1.jar#manifest.mf:

Manifest-Version: 1.0Name: com/fjn/java/util/jar/Sealed: true

java_sealed_v2.jar#manifest.mf: 

Manifest-Version: 1.0Sealed: false

執行測試,結果如下: 

id: 100, name: hellotruefile:/E:/workspace/Test/lib/java_sealed_v1.jarException in thread "main" java.lang.SecurityException: sealing violation: package com.fjn.java.util.jar is sealed    at java.net.URLClassLoader.getAndVerifyPackage(Unknown Source)    at java.net.URLClassLoader.defineClass(Unknown Source)    at java.net.URLClassLoader.access$100(Unknown Source)    at java.net.URLClassLoader$1.run(Unknown Source)    at java.net.URLClassLoader$1.run(Unknown Source)    at java.security.AccessController.doPrivileged(Native Method)    at java.net.URLClassLoader.findClass(Unknown Source)    at java.lang.ClassLoader.loadClass(Unknown Source)    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)    at java.lang.ClassLoader.loadClass(Unknown Source)    at com.java.sealtest.SealedTest.main(SealedTest.java:14)

 

從這個結果上看,應該是程式執行到ClassB objB=new ClassB();這句時出錯了。 

在執行這個語句時,要載入ClassB,jvm在java_sealed_v2.jar中找到了ClassB,找到後要執行getAndVerifyPackage方法。在這個過程中出錯。

 

現在來看一下URLClassLoader#getAndVerifyPackage()方法:

private Package getAndVerifyPackage(String pkgname,                                        Manifest man, URL url) {// 從當前ClassLoader已經載入的包集合中尋找,這個包是否已經載入過了// 如果已經載入過了,傳回值pkg就不是null.        Package pkg = getPackage(pkgname);        if (pkg != null) {            // Package found, so check package sealing.            if (pkg.isSealed()) {                // Verify that code source URL is the same.                if (!pkg.isSealed(url)) {                    throw new SecurityException(                        "sealing violation: package " + pkgname + " is sealed");                }            } else {                // Make sure we are not attempting to seal the package                // at this code source URL.                if ((man != null) && isSealed(pkgname, man)) {                    throw new SecurityException(                        "sealing violation: can‘t seal package " + pkgname +                        ": already loaded");                }            }        }        return pkg;    }

從ClassLoader已經載入的包中找到了java_sealed_v1.jar下的com.fjn.java.util.jar 包,這個包是密封的,所以就拋出錯誤了。 

從上面這段代碼,還能看出另外一個問題:如果一個未密封的包被載入了,再次載入同包名不同jar檔案中類時,也會出錯。

 

 

測試3)java_sealed_v1.jar中的sealed禁用、java_sealed_v2.jar中的sealed啟用。這個測試就是用於驗證上面說的另外一種情況的。

 

此時清單狀態如下:

java_sealed_v1.jar#manifest.mf:

Manifest-Version: 1.0Name: com/fjn/java/util/jar/Sealed: false

java_sealed_v2.jar#manifest.mf: 

Manifest-Version: 1.0Sealed: true

測試結果如下: 

id: 100, name: hellofalsefile:/E:/workspace/Test/lib/java_sealed_v1.jarException in thread "main" java.lang.SecurityException: sealing violation: can‘t seal package com.fjn.java.util.jar: already loaded    at java.net.URLClassLoader.getAndVerifyPackage(Unknown Source)    at java.net.URLClassLoader.defineClass(Unknown Source)    at java.net.URLClassLoader.access$100(Unknown Source)    at java.net.URLClassLoader$1.run(Unknown Source)    at java.net.URLClassLoader$1.run(Unknown Source)    at java.security.AccessController.doPrivileged(Native Method)    at java.net.URLClassLoader.findClass(Unknown Source)    at java.lang.ClassLoader.loadClass(Unknown Source)    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)    at java.lang.ClassLoader.loadClass(Unknown Source)    at com.java.sealtest.SealedTest.main(SealedTest.java:14)

測試結果驗證了上面的說法。 

 

 

從這幾個測試中知道:

在載入類的時候,如果要載入的類 所在的包,在多個jar檔案中,只要有一個被指定了sealed,運行時就有可能出現問題。

如果一個package(package名相同即為同一個包),存在於多個jar檔案中,最好是都不要限制為sealed。

在一個project中,如果某個jar多個版本共存時,一定要注意sealed的設定。

 

Java Jar : sealed in manifest

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.