Home >Java >javaTutorial >Detailed introduction to Java dynamic class loading and reloading

Detailed introduction to Java dynamic class loading and reloading

不言
不言forward
2018-10-17 16:28:275174browse

This article brings you a detailed introduction to Java dynamic class loading and reloading. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

Classes can be loaded and reloaded at runtime in Java, although it is not as simple as we think. This article will explain when and how to load and reload classes in Java.
You can argue whether dynamically loading classes is part of Java reflection or part of Java core. Anyway, I put it in Java Reflection for lack of a better place to put it.

Class Loader

All classes in a Java program are loaded using some subclasses of java.lang.ClassLoader. Therefore, dynamically loaded classes must also use a subclass of java.lang.ClassLoader.
When a class is loaded, the classes it references will also be loaded. Class loading mode loads recursively until all required classes are loaded. This may not be all classes for the application. Unreferenced classes are not loaded until they are referenced.

Class loading hierarchy

Class loading in Java is organized into hierarchies. When you create a standalone ClassLoader, you must provide a parent ClassLoader. If a ClassLoader is asked to load a class, it will ask its parent ClassLoader to load it. If the parent class loader cannot find the class, the child class loader will try to load it itself.

Class loading

The steps for the class loader to load a class are as follows:

  1. Check whether the class has been loaded

  2. If the class is not loaded, request the parent class loader to load it

  3. If the parent class loader cannot load the class, try to use the current class loader to load it

When you implement a class loader that can overload classes, you need to deviate a little from this sequence. The parent class loader should not be asked to load the class to be reloaded. More on that later.

Dynamic Class Loading

Dynamic loading of classes is very simple. All you need to do is get a ClassLoader and call its loadClass() method. An example is as follows:

public class MainClass {

  public static void main(String[] args){

    ClassLoader classLoader = MainClass.class.getClassLoader();

    try {
        Class aClass = classLoader.loadClass("com.jenkov.MyClass");
        System.out.println("aClass.getName() = " + aClass.getName());
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

}

Dynamic Class Reloading

Dynamic class reloading has some challenges. Java's built-in class loader always checks whether the class has been loaded before loading it. Therefore, it is not possible to reload a class using Java's built-in class loader. To reload a class you must implement your own ClassLoader subclass.
Even with custom subclasses of class loaders, there are challenges. All loaded classes need to be linked. This method is final and therefore cannot be overridden by your ClassLoader subclasses. The resolve() method does not allow a ClassLoader instance to link to a class twice. Therefore, whenever you need to reload a class, you must recreate an instance of the ClassLoader class. It's not impossible, but one has to know when to design the class to reload.

Class overloading code design

As mentioned above, the ClassLoader that loads the specified class cannot be used to reload this class. Therefore, a different ClassLoader must be used to load this class. However, this creates new problems.
Each class loaded in a Java program is identified by its fully qualified name (package name class name) and is loaded by a ClassLoader instance. This means that the class MyObject loaded by class loader A is different from the same class MyObject loaded by class loader B. The simulation code is as follows:

MyObject object = (MyObject)
    myClassReloadingFactory.newInstance("com.jenkov.MyObject");

Note how the class MyObject is referenced in the code as a variable of type object. This causes the MyObject class to be loaded by the class loader that already loaded the resident code for this class.
If the myClassReloadingFactory object factory uses a different class loader than the resident code to load MyObject, you cannot cast the reloaded Object type variable MyObject to the MyObject type. Because the two MyObjects are loaded by different class loaders, they are considered different classes, even though they have the same fully qualified name. Attempting to cast an object's class as a reference to another class will throw a ClassCastException.
It is possible to get around this limitation, but you have to change your code in two ways:

  1. Use interface as variable type, and only reload the implementation class

  2. Use superclass as variable type and only reload subclasses

Here is the sample code:

MyObjectInterface object = (MyObjectInterface)
    myClassReloadingFactory.newInstance("com.jenkov.MyObject");
MyObjectSuperclass object = (MyObjectSuperclass)
    myClassReloadingFactory.newInstance("com.jenkov.MyObject");

If the variable type is Interface or superclass, the above code will run normally, the interface or superclass will not be reloaded when the implementation or subclass is reloaded.
In order for the above code to run normally, you certainly need to implement your own class loader so that the interface or super class is loaded by its parent class. When your class loader is asked to load MyObject, it will also be asked to load the MyObjectInterface interface or MyObjectSuperclass class, because they are referenced internally by the MyObject class. Your class loader must delegate class loading to the same class loader that loaded the interface or superclass.

类加载器加载/重新加载示例

上文包含了很多内容。让我们看一下简单的示例。下面是一个简单的ClassLoader子类。注意它如何将类加载委托给它的父类,除了它想要重装的一个类之外。如果类加载被委派给了它的父类,它以后将不能被重新加载。记住,一个类只能被同一个ClassLoader实例加载。
如前所述,这只是一个示例,它显示了类加载器的行为的基本知识。这并不是一个你的类加载器的生产就绪的模板。你的类加载器可能并不仅限于一个类,可能是一个你想要重新加载的类的集合。此外,你也不能硬编码class path。

public class MyClassLoader extends ClassLoader{

    public MyClassLoader(ClassLoader parent) {
        super(parent);
    }

    public Class loadClass(String name) throws ClassNotFoundException {
        if(!"reflection.MyObject".equals(name))
                return super.loadClass(name);

        try {
            String url = "file:C:/data/projects/tutorials/web/WEB-INF/" +
                            "classes/reflection/MyObject.class";
            URL myUrl = new URL(url);
            URLConnection connection = myUrl.openConnection();
            InputStream input = connection.getInputStream();
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
            int data = input.read();

            while(data != -1){
                buffer.write(data);
                data = input.read();
            }

            input.close();

            byte[] classData = buffer.toByteArray();

            return defineClass("reflection.MyObject",
                    classData, 0, classData.length);

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

}

下面是使用MyClassLoader的示例:

public static void main(String[] args) throws
    ClassNotFoundException,
    IllegalAccessException,
    InstantiationException {

    ClassLoader parentClassLoader = MyClassLoader.class.getClassLoader();
    MyClassLoader classLoader = new MyClassLoader(parentClassLoader);
    Class myObjectClass = classLoader.loadClass("reflection.MyObject");

    AnInterface2       object1 =
            (AnInterface2) myObjectClass.newInstance();

    MyObjectSuperClass object2 =
            (MyObjectSuperClass) myObjectClass.newInstance();

    //create new class loader so classes can be reloaded.
    classLoader = new MyClassLoader(parentClassLoader);
    myObjectClass = classLoader.loadClass("reflection.MyObject");

    object1 = (AnInterface2)       myObjectClass.newInstance();
    object2 = (MyObjectSuperClass) myObjectClass.newInstance();

}

reflection.MyObject类是由自定义类加载器加载的。注意,它是如何继承一个超类、实现一个接口的。这只是为了这个例子。在你的代码中,只需要两个中的一个,继承超类或实现接口。

public class MyObject extends MyObjectSuperClass implements AnInterface2{
    //... body of class ... override superclass methods
    //    or implement interface methods
}

The above is the detailed content of Detailed introduction to Java dynamic class loading and reloading. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:segmentfault.com. If there is any infringement, please contact admin@php.cn delete