欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

java 详解类加载器的双亲委派及打破双亲委派

程序员文章站 2024-03-08 10:07:04
java 详解类加载器的双亲委派及打破双亲委派 一般的场景中使用java默认的类加载器即可,但有时为了达到某种目的又不得不实现自己的类加载器,例如为了达到类库的互相隔离,...

java 详解类加载器的双亲委派及打破双亲委派

一般的场景中使用java默认的类加载器即可,但有时为了达到某种目的又不得不实现自己的类加载器,例如为了达到类库的互相隔离,例如为了达到热部署重加载功能。这时就需要自己定义类加载器,每个类加载器加载各自的类库资源,以此达到资源隔离效果。在对资源的加载上可以沿用双亲委派机制,也可以打破双亲委派机制。

一、沿用双亲委派机制自定义类加载器很简单,只需继承classloader类并重写findclass方法即可。如下例子:

①先定义一个待加载的类test,它很简单,只是在构建函数中输出由哪个类加载器加载。

public class test {

  public test(){
    system.out.println(this.getclass().getclassloader().tostring());
  }

}

②定义一个testclassloader类继承classloader,重写findclass方法,此方法要做的事情是读取test.class字节流并传入父类的defineclass方法即可。然后就可以通过自定义累加载器testclassloader对test.class进行加载,完成加载后会输出“testloader”。

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

}

二、打破双亲委派机制则不仅要继承classloader类,还要重写loadclass和findclass方法,如下例子:

①定义test类。

public class test {
  public test(){
    system.out.println(this.getclass().getclassloader().tostring());
  }
}

②重新定义一个继承classloader的testclassloadern类,这个类与前面的testclassloader类很相似,但它除了重写findclass方法外还重写了loadclass方法,默认的loadclass方法是实现了双亲委派机制的逻辑,即会先让父类加载器加载,当无法加载时才由自己加载。这里为了破坏双亲委派机制必须重写loadclass方法,即这里先尝试交由system类加载器加载,加载失败才会由自己加载。它并没有优先交给父类加载器,这就打破了双亲委派机制。

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

}

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!