如何在JVM中再加载一次java.util.TimeZone

时间:2019-06-27 07:26:51

标签: java classloader

我创建了自定义类加载器:

new URLClassLoader(urls, Thread.currentThread().getContextClassLoader());

其中url是new Url("java.util.TimeZone")

之后,我通过名称加载课程:

Class<?> newTimeZoneClass = loader.loadClass("java.util.TimeZone");

newTimeZoneClass==TimeZone.class返回true

我的类加载器从父加载器加载类的主要原因。 如何解决?

2 个答案:

答案 0 :(得分:1)

public URLClassLoader(URL[] urls, ClassLoader parent):的Java文档中提到

  

为给定的URL构造一个新的URLClassLoader。网址将是         首先,按照为类和资源指定的顺序搜索         在指定的父类加载器中搜索。

我假设您应该通过传递AccessControlContext对象-CustomClassLoader ccl = new CustomClassLoader();创建URLClassLoader(URL[] urls, ClassLoader parent, AccessControlContext acc)或使用其他构造函数 或URLClassLoader(URL[] urls, AccessControlContext acc)

有些文章介绍了如何创建新的类加载器:

https://www.baeldung.com/java-classloaders

https://www.javaworld.com/article/2077260/learn-java-the-basics-of-java-

https://www.oodlestechnologies.com/blogs/Creating-Custom-Class-Loader-In-JAVA/class-loaders.html

答案 1 :(得分:1)

您不能这样做。 Java安全模型阻止任何类装入器在“ java。*”层次结构中创建类。这是用JVM的本机代码硬编码的,因此没有解决方法。

此外,标准类加载器遵循委托模型,要求父类加载器在尝试加载类之前先进行加载,因此您始终会获得相同的类实例。应用程序容器使用特殊的类加载器来反转针对特定于应用程序的类的委派。

反正有几种方法。

首先,TimeZone是一个抽象类,实际的实现通常是sun.util.calendar.ZoneInfo。由于这不在“ java。*”层次结构中,因此您可以在类加载器中创建多个副本。

第二,您可以继承TimeZone的子类,并将所有方法委托给JVM提供的实例,同时添加自己的功能。我使用它来使TimeZone实例在我的某些应用程序中成为单例。

第三,由于JDK是开源的,因此您可以将TimeZone的所有代码及其子类复制到您自己的应用程序中,然后可以根据需要选择该类的多个版本。

如果您想更改TimeZone中的静态方法返回的TimeZone实例,则这些实例将委托给ZoneInfo,并且您将不得不使用反射来更改结果。如果您知道Aspect-J或同等学历,也可以拦截该呼叫。