自定义ClassLoader,如何使用?
Custom ClassLoader, how to use?
我正在尝试使用自定义 class 加载程序来加载应用程序所需的所有依赖项。我已经在网站后实施了 customerClassLoader:https://www.javacodegeeks.com/2013/03/java-handmade-classloader-isolation.html
但是,我不明白如何告诉我的应用程序在需要时使用自定义 classLoader。
例如:比方说,我有一种方法可以像下面这样发出 http 请求。我如何告诉应用程序使用自定义 classLoader 来加载所需的 jar?
private HttpResponse get() {
HttpClient client = HttpClientBuilder.create().build();
HttpGet request = new HttpGet(url);
HttpResponse response = client.execute(request);
return response;
}
您可以执行以下操作;
Thread.currentThread().setContextClassLoader(new MyCustomClassLoader());
Java 隐式使用 ClassLoader
当你使用 new
, import
关键字时,jvm 将使用当前 class 的 classloader 来加载依赖的 classes,因此您可以使用自定义 classloader 通过使用 classloader.loadclass
和 bootstrap
只是 运行 一个属于您的目标 class 实例的方法。下面是一个例子。
有一个 class Target
依赖于 class DateFormatter
包含在 spring-context
中,并且有一个名为 start
.
import org.springframework.format.datetime.DateFormatter;
public class Target {
private static DateFormatter dateFormatter;
public void start(){
System.out.println(this.getClass().getClassLoader());
dateFormatter=new DateFormatter();
System.out.println(dateFormatter);
}
}
接下来我们将上面的代码编译打包成一个名为target.jar
的jar,存放在D:\test\target.jar
.
接下来,我们在另一个 jar 中声明一个 class BootStrap
,它将调用 Target
实例的方法 start
。 BootStrap
class 将通过相同的 classloader
动态加载 target.jar
和 spring-context
jar 文件,这是一个 URLClassLoader
实例。因此,Target
实例中的方法 start
可以访问 spring-context
.
中定义的 DateFormatter
class
public class BootStrap {
public static void main(String[] args) throws Exception{
URL url = new URL("http://maven.aliyun.com/nexus/content/groups/public/org/springframework/spring-context/4.3.1.RELEASE/spring-context-4.3.1.RELEASE.jar?spm=0.0.0.0.kG1Pdw&file=spring-context-4.3.1.RELEASE.jar");
URL url2= (new File("D:\test\target.jar").toURI().toURL());
URLClassLoader classLoader = new URLClassLoader(new URL[]{url,url2});
Class<?> clz = classLoader.loadClass("com.zhuyiren.Target");
Object main = clz.newInstance();
Method test = clz.getMethod("start");
test.invoke(main);
}
}
最后,运行 BootStrap
主要方法。有两点很重要:
BootStrap
class和Target
class不属于同一个jar文件。
target.jar
未存储在 CLASSPATH
路径中。
这两点可以保证AppClassLoader
找不到和加载Target
class。由于 class 加载器的机制,jvm 将使用自定义加载 Target
。当然,你可以通过将 URLClassLoader classLoader = new URLClassLoader(new URL[]{url,url2});
更改为 URLClassLoader classLoader = new URLClassLoader(new URL[]{url, url2}, ClassLoader.getSystemClassLoader().getParent());
来保证
我们可以看到结果:
java.net.URLClassLoader@e9e54c2
org.springframework.format.datetime.DateFormatter@4dd8dc3
这意味着我们可以成功访问spring-context
jar文件中定义的DateFormatter
实例,而spring-context
没有存储在CLASSPATH
中,但我们是使用自定义类加载器加载和使用它。
我正在尝试使用自定义 class 加载程序来加载应用程序所需的所有依赖项。我已经在网站后实施了 customerClassLoader:https://www.javacodegeeks.com/2013/03/java-handmade-classloader-isolation.html
但是,我不明白如何告诉我的应用程序在需要时使用自定义 classLoader。
例如:比方说,我有一种方法可以像下面这样发出 http 请求。我如何告诉应用程序使用自定义 classLoader 来加载所需的 jar?
private HttpResponse get() {
HttpClient client = HttpClientBuilder.create().build();
HttpGet request = new HttpGet(url);
HttpResponse response = client.execute(request);
return response;
}
您可以执行以下操作;
Thread.currentThread().setContextClassLoader(new MyCustomClassLoader());
Java 隐式使用 ClassLoader
当你使用 new
, import
关键字时,jvm 将使用当前 class 的 classloader 来加载依赖的 classes,因此您可以使用自定义 classloader 通过使用 classloader.loadclass
和 bootstrap
只是 运行 一个属于您的目标 class 实例的方法。下面是一个例子。
有一个 class Target
依赖于 class DateFormatter
包含在 spring-context
中,并且有一个名为 start
.
import org.springframework.format.datetime.DateFormatter;
public class Target {
private static DateFormatter dateFormatter;
public void start(){
System.out.println(this.getClass().getClassLoader());
dateFormatter=new DateFormatter();
System.out.println(dateFormatter);
}
}
接下来我们将上面的代码编译打包成一个名为target.jar
的jar,存放在D:\test\target.jar
.
接下来,我们在另一个 jar 中声明一个 class BootStrap
,它将调用 Target
实例的方法 start
。 BootStrap
class 将通过相同的 classloader
动态加载 target.jar
和 spring-context
jar 文件,这是一个 URLClassLoader
实例。因此,Target
实例中的方法 start
可以访问 spring-context
.
DateFormatter
class
public class BootStrap {
public static void main(String[] args) throws Exception{
URL url = new URL("http://maven.aliyun.com/nexus/content/groups/public/org/springframework/spring-context/4.3.1.RELEASE/spring-context-4.3.1.RELEASE.jar?spm=0.0.0.0.kG1Pdw&file=spring-context-4.3.1.RELEASE.jar");
URL url2= (new File("D:\test\target.jar").toURI().toURL());
URLClassLoader classLoader = new URLClassLoader(new URL[]{url,url2});
Class<?> clz = classLoader.loadClass("com.zhuyiren.Target");
Object main = clz.newInstance();
Method test = clz.getMethod("start");
test.invoke(main);
}
}
最后,运行 BootStrap
主要方法。有两点很重要:
BootStrap
class和Target
class不属于同一个jar文件。target.jar
未存储在CLASSPATH
路径中。
这两点可以保证AppClassLoader
找不到和加载Target
class。由于 class 加载器的机制,jvm 将使用自定义加载 Target
。当然,你可以通过将 URLClassLoader classLoader = new URLClassLoader(new URL[]{url,url2});
更改为 URLClassLoader classLoader = new URLClassLoader(new URL[]{url, url2}, ClassLoader.getSystemClassLoader().getParent());
我们可以看到结果:
java.net.URLClassLoader@e9e54c2
org.springframework.format.datetime.DateFormatter@4dd8dc3
这意味着我们可以成功访问spring-context
jar文件中定义的DateFormatter
实例,而spring-context
没有存储在CLASSPATH
中,但我们是使用自定义类加载器加载和使用它。