Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom ClassLoader, how to use?

I am trying to use a custom class loader to load all the dependencies needed for the application. I've implemented the customerClassLoader following the site: https://www.javacodegeeks.com/2013/03/java-handmade-classloader-isolation.html

However, I dont understand how to tell my application to use the custom classLoader whenever needed.

For instance: Lets say, I have a method to make http request like below. How can I tell the application to use the custom classLoader to load the required jars?

private HttpResponse get() {
    HttpClient client = HttpClientBuilder.create().build();
    HttpGet request = new HttpGet(url);
    HttpResponse response = client.execute(request);
    return response;
}
like image 937
Minisha Avatar asked Aug 13 '17 03:08

Minisha


People also ask

When would you use a custom ClassLoader?

Custom class loaders are useful in larger architectures consisting of several module/applications. Here are the advantages of the custom class loader: Provides Modular architecture Allows to define multiple class loader allowing modular architecture.

How does a ClassLoader work internally?

Extension ClassLoader searches for the class in the Extension Classpath(JDK/JRE/LIB/EXT). If the class is available then it is loaded, if not the request is delegated to the Application ClassLoader. Application ClassLoader searches for the class in the Application Classpath.

How does a ClassLoader work in Java?

Class loaders are responsible for loading Java classes dynamically to the JVM (Java Virtual Machine) during runtime. They're also part of the JRE (Java Runtime Environment). Therefore, the JVM doesn't need to know about the underlying files or file systems in order to run Java programs thanks to class loaders.

Can we create our own ClassLoader in Java?

We will create our own ClassLoader by extending the ClassLoader class and overriding the loadClass(String name) method. If the class name will start from com. journaldev then we will load it using our custom class loader or else we will invoke the parent ClassLoader loadClass() method to load the class.


1 Answers

Java uses ClassLoader implicitly when you use new, import keyword, the jvm will use the current class's classloader to load the dependent classes, so you can use the custom classloader to load a bootstrap class explicitly by using classloader.loadclass, and the bootstrap just runs a method belonging to your target class instance. An example follows.

There is a class Target that depends on the class DateFormatter which is included in the spring-context, and has a method named 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);
    }
}

Next, we compile and package the above code as a jar named target.jar, which is stored at D:\\test\\target.jar.

Next, we declare a class BootStrap in another jar that will call the method start of Target instance. The BootStrap class will dynamically load the target.jar and spring-context jar files by the same classloader which is a URLClassLoader instance. Because of this, the method start in Target instance can access the DateFormatter class that is defined in spring-context.

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);
    }
}

Finally, run the BootStrap main method. There are two important thing:

  1. The BootStrap class and Target class don't belong to a same jar file.
  2. The target.jar is not stored in CLASSPATH path.

These 2 point can make sure that the AppClassLoader can not find and load the Target class. Because of the mechanism of class loader, jvm will use the custom load the Target. Of course, you can guarantee it by changing the URLClassLoader classLoader = new URLClassLoader(new URL[]{url,url2}); to URLClassLoader classLoader = new URLClassLoader(new URL[]{url, url2}, ClassLoader.getSystemClassLoader().getParent());

And we can see the result:

java.net.URLClassLoader@e9e54c2
org.springframework.format.datetime.DateFormatter@4dd8dc3

That means we can access the DateFormatter instance which is defined in spring-context jar file successfully, while the spring-context is not stored in CLASSPATH, but we are using the custom clasloader to load and use it.

like image 192
dabaicai Avatar answered Sep 21 '22 12:09

dabaicai