java 详解类加载器的双亲委派及打破双亲委派
这里有新鲜出炉的 Java 函数式编程, 程序狗速度看过来!
Java 程序设计语言
java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言, 是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 程序设计语言和 Java 平台 (即 JavaEE(j2ee), JavaME(j2me), JavaSE(j2se)) 的总称
这篇文章主要介绍了 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();
- }
- }
- }
来源: http://www.phperz.com/article/18/0210/358846.html