java explains the class loader's parent delegate and the break parent delegate

  • 2020-05-30 20:02:11
  • OfStack

java explains the class loader's parent delegate and the break parent delegate

You can use Java's default class loader in a 1-like scenario, but sometimes you have to implement your own class loader for some purpose, such as to isolate the class libraries from each other, such as to achieve the hot deployment reload function. At this point, you need to define your own class loader, and each class loader loads its own class library resources to achieve the effect of resource isolation. You can use or break the parent delegate mechanism for loading resources.

1. Using the parent delegate mechanism to customize the class loader is as simple as inheriting the ClassLoader class and rewriting the findClass method. Here are some examples:

Define a class Test to be loaded, it is very simple, just in the build function output by which class loader load.


public class Test {

  public Test(){
    System.out.println(this.getClass().getClassLoader().toString());
  }

}

(2) define a class TestClassLoader ClassLoader inheritance, override the findClass method, this method is to read Test.class byte stream and pass in the parent class defineClass method. Test.class can then be loaded with a custom loader, TestClassLoader, and "TestLoader" will be output.


public class TestClassLoader extends ClassLoader {

  private String name;

  public TestClassLoader(ClassLoader parent, String name) {
    super(parent);
    this.name = name;
  }

  @Override
  public String toString() {
    return this.name;
  }

  @Override
  public Class<?> findClass(String name) {

    InputStream is = null;
    byte[] data = null;
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try {
      is = new FileInputStream(new File("d:/Test.class"));
      int c = 0;
      while (-1 != (c = is.read())) {
        baos.write(c);
      }
      data = baos.toByteArray();
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      try {
        is.close();
        baos.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    return this.defineClass(name, data, 0, data.length);
  }

  public static void main(String[] args) {
    TestClassLoader loader = new TestClassLoader(
        TestClassLoader.class.getClassLoader(), "TestLoader");
    Class clazz;
    try {
      clazz = loader.loadClass("test.classloader.Test");
      Object object = clazz.newInstance();
    } catch (Exception e) {
      e.printStackTrace();
    } 
  }

}

2. Breaking the parent delegate mechanism requires not only inheriting the ClassLoader class, but also rewriting the loadClass and findClass methods, as shown in the following example:

Define Test class.


public class Test {
  public Test(){
    System.out.println(this.getClass().getClassLoader().toString());
  }
}

This class is similar to the previous TestClassLoader class, but it overrides the loadClass method in addition to the findClass method. The default loadClass method implements the logic of the parent delegate mechanism, that is, it will let the parent class loader load first, and only load by itself when it cannot be loaded. In order to break the parent delegate mechanism, the loadClass method must be overridden, which means that the System class loader will try to load the loadClass class first, and the System class loader will not load the loadClass class until it fails. It does not give priority to the parent class loader, which breaks the parent delegate mechanism.


public class TestClassLoaderN extends ClassLoader {

  private String name;

  public TestClassLoaderN(ClassLoader parent, String name) {
    super(parent);
    this.name = name;
  }

  @Override
  public String toString() {
    return this.name;
  }

  @Override
  public Class<?> loadClass(String name) throws ClassNotFoundException {
    Class<?> clazz = null;
    ClassLoader system = getSystemClassLoader();
    try {
      clazz = system.loadClass(name);
    } catch (Exception e) {
      // ignore
    }
    if (clazz != null)
      return clazz;
    clazz = findClass(name);
    return clazz;
  }

  @Override
  public Class<?> findClass(String name) {

    InputStream is = null;
    byte[] data = null;
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try {
      is = new FileInputStream(new File("d:/Test.class"));
      int c = 0;
      while (-1 != (c = is.read())) {
        baos.write(c);
      }
      data = baos.toByteArray();
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      try {
        is.close();
        baos.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    return this.defineClass(name, data, 0, data.length);
  }

  public static void main(String[] args) {
    TestClassLoaderN loader = new TestClassLoaderN(
        TestClassLoaderN.class.getClassLoader(), "TestLoaderN");
    Class clazz;
    try {
      clazz = loader.loadClass("test.classloader.Test");
      Object object = clazz.newInstance();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

}

Thank you for reading, I hope to help you, thank you for your support of this site!


Related articles: