Java 使用自定义类装入器进行静态变量隔离
我有这个密码Java 使用自定义类装入器进行静态变量隔离,java,Java,我有这个密码 MyClassloader loader = new MyClassloader(); Class c = loader.loadClass(classToLoad); Thread.currentThread().setContextClassLoader(loader); MyClass myClass = (MyClass) c.newInstance(); 类加载器代码是 public MyClassload
MyClassloader loader = new MyClassloader();
Class c = loader.loadClass(classToLoad);
Thread.currentThread().setContextClassLoader(loader);
MyClass myClass = (MyClass) c.newInstance();
类加载器代码是
public MyClassloader) throws IOException {
super(Thread.currentThread().getContextClassLoader());
}
类加载工作正常问题在于静态变量没有被隔离,因此如果在MyClass
中设置了一个静态变量,那么所有其他MyClass
实例都会得到相同的值
在什么情况下可以隔离静态变量?您将委托给同一类加载器。所以你看不出有什么不同 你该怎么办在类加载器中实现类加载,不要只是委托。例如,从URLClassLoader继承类加载器,并正确初始化它(这意味着,为类加载器提供一个有效的类路径来初始化它)。然后,您将看到,您的类加载器加载的类与标准类加载器加载的类并不相同,因此,它们的静态成员将不同 通常,上下文类加载器是从URLClassLoader继承的,因此您不必花费太多时间为其配置类路径。相反,要初始化类加载器,可以重用上下文类加载器的URL,如下所示:
public class MyIndependentClassLoader extends URLClassLoader {
public MyIndependentClassLoader(){
super(((URLClassLoader) Thread.currentThread().getContextClassLoader()).getURLs());
}
}
现在可以使用类加载器检查静态成员
这种方法和最初的方法有什么区别
你知道类也是对象(特殊类型):它们有自己的成员变量,name,serialVersionId,annotationData等,还有自己的方法,newInstance(),getFields(),getMethods(),
等
Class c = loader.loadClass("com.my.package.MyClassX");
您将获得c
,这是一个描述加载的类“some class name”的对象。这个c
不仅允许创建实例,还可以保存所有静态成员
在代码中:类加载器不会直接加载类。相反,它将委托给上下文类加载器。这就是为什么要比较两个加载的类
Class c = loader.loadClass("com.my.package.MyClassX");
Class ct = Thread.currentThread().getContextClassLoader().loadClass("com.my.package.MyClassX");
您将看到,c
和ct
是同一个对象。如果您调用c.equals(ct)
,它将为您提供true
。如果你调用c==ct
,它也会给你true
。这意味着,这是同一个类实例。这就是为什么——当然——如果你检查静态变量,它们将是相同的。如果在一个类中更改静态变量,它也将在另一个类中更改,反之亦然
在我的代码中:本质上的区别是,类加载器自己加载类。它不会将其委托给其他类加载器。我建议从URLClassLoader
扩展它,以简化我们的实现(否则您必须从头开始实现处理类路径、目录、jar、可见性、缓存等)。为了避免一步一步地添加每个类路径元素,我建议使用相同的类路径(相同的目录列表、JAR等)作为上下文类装入器。因此,我们的类加载器将能够找到与上下文类加载器相同的类。
现在检查这个类加载器加载的类。让我们称之为ci
:
Class ci = new MyIndependentClassLoader().loadClass("com.my.package.MyClassX");
如果比较这些类,您将看到c.equals(ci)
给出false
。也就是说,它们是不同的。这就是为什么他们也有独立的静态成员。如果在一个类中更改静态成员,ct
,则在另一个类中它不会更改,ci
,反之亦然。可能重复@MohammedHousseynTaleb该问题与此问题相反。在您的示例中,执行扩展类加载器
和扩展URLClassLoader
有什么区别?原因是简化类的加载。当然,不需要使用URLClassLoader就可以做到这一点。然后你必须实现类的解析/加载(你的类加载器将如何加载X类的字节码?)我的意思是我不明白你的代码和我的代码在“静态变量隔离”方面有什么区别?简单地说:你的类加载器返回与上下文类加载器相同的类实例。没有隔离,因为这是同一个类实例:内存中的同一个位置、相同的静态成员等。要实现隔离,不要委托给另一个类装入器,而是“亲自”直接装入类。然后您将得到两个不同的类实例,它们具有完全独立的静态成员。我在上面的回答中添加了更多细节。您的类加载器只是上下文类加载器的“捷径”。它提供与上下文类加载器完全相同的结果。我实际的类加载器代码是公共类MyClassloader Extendes类加载器{public MyClassloader()抛出IOException{super(Thread.currentThread().getContextClassLoader());}
,您能指出这与您的示例有什么不同吗?与你的例子相反,这不是授权。