当前位置: 移动技术网 > IT编程>开发语言>Java > java 详解类加载器的双亲委派及打破双亲委派

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

2019年07月22日  | 移动技术网IT编程  | 我要评论
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();
    }
  }

}

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

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网