码迷,mamicode.com
首页 > 编程语言 > 详细

Java Jar : sealed in manifest

时间:2015-07-13 10:02:30      阅读:289      评论:0      收藏:0      [点我收藏+]

标签:

在上一篇文章中说到了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 fs1194361820@163.com 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 fs1194361820@163.com 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.0

Name: com/fjn/java/util/jar/
Sealed: fasle

 

java_sealed_v2.jar的清单: 

Manifest-Version: 1.0
Sealed: 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: hello
false
file:/E:/workspace/Test/lib/java_sealed_v1.jar
com.fjn.java.util.jar.ClassB@a8f0b4
false
file:/E:/workspace/Test/lib/java_sealed_v2.jar
id: 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.0

Name: com/fjn/java/util/jar/
Sealed: true

java_sealed_v2.jar#manifest.mf: 

Manifest-Version: 1.0
Sealed: false

执行测试,结果如下: 

id: 100, name: hello
true
file:/E:/workspace/Test/lib/java_sealed_v1.jar
Exception 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.0

Name: com/fjn/java/util/jar/
Sealed: false

java_sealed_v2.jar#manifest.mf: 

Manifest-Version: 1.0
Sealed: true

测试结果如下: 

id: 100, name: hello
false
file:/E:/workspace/Test/lib/java_sealed_v1.jar
Exception 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

标签:

原文地址:http://www.cnblogs.com/f1194361820/p/4642151.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!