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

一般的场景中使用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();
        }
    }

}

========广告时间========

鄙人的新书《Tomcat内核设计剖析》已经在京东销售了,有需要的朋友可以到 https://item.jd.com/12185360.html 进行预定。感谢各位朋友。

为什么写《Tomcat内核设计剖析》

=========================

欢迎关注:

时间: 2024-09-29 09:58:17

类加载器的双亲委派及打破双亲委派的相关文章

Java魔法堂:类加载器入了个门

一.前言   <Java魔法堂:类加载机制入了个门>中提及整个类加载流程中只有加载阶段作为码农的我们可以入手干预,其余均由JVM处理.本文将记录加载阶段的核心组件--类加载器的相关信息,以便日后查阅.若有纰漏请大家指正,谢谢.   注意:以下内容基于JDK7和HotSpot VM.   二.类加载器种类及其关系 从上图可知Java主要有4种类加载器 1. Bootstrap ClassLoader(引导类加载器):作为JVM的一部分无法在应用程序中直接引用,由C/C++实现(其他JVM可能通过

Java类加载器(一)——类加载器层次与模型

类加载器   虚拟机设计团队把类加载阶段中的"通过一个类的全限定名来获取描述此类的二进制字节流"这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类.实现这个动作的代码模块称为"类加载器". 类加载器层次(等级)   从JVM的角度来讲,只存在两种不同的类加载器.   第一类是启动类加载器(Bootstrap ClassLoader):这个类加载器主要加载JVM自身工作需要的类.这个类加载器由C++语言实现(特指HotSpot),是虚拟机

一篇文章读懂Java类加载器

Java类加载器算是一个老生常谈的问题,大多Java工程师也都对其中的知识点倒背如流,最近在看源码的时候发现有一些细节的地方理解还是比较模糊,正好写一篇文章梳理一下. 关于Java类加载器的知识,网上一搜一大片,我自己也看过很多文档,博客.资料虽然很多,但还是希望通过本文尽量写出一些自己的理解,自己的东西.如果只是重复别人写的内容那就失去写作的意义了. 类加载器结构 类加载器结构 名称解释: 根类加载器,也叫引导类加载器.启动类加载器.由于它不属于Java类库,这里就不说它对应的类名了,很多人喜

后台(30)——类加载器ClassLoader

探索Android软键盘的疑难杂症 深入探讨Android异步精髓Handler 详解Android主流框架不可或缺的基石 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)- 核心基础 Android多分辨率适配框架(2)- 原理剖析 Android多分辨率适配框架(3)- 使用指南 自定义View系列教程00–推翻自己和过往,重学自定义View 自定义View系列教程01–常用工具介绍 自定义View系列教程02–onMeasure源码详尽分析 自定义View

深入解析Java中的Class Loader类加载器_java

类加载的过程类加载器的主要工作就是把类文件加载到JVM中.如下图所示,其过程分为三步: 1.加载:定位要加载的类文件,并将其字节流装载到JVM中: 2.链接:给要加载的类分配最基本的内存结构保存其信息,比如属性,方法以及引用的类.在该阶段,该类还处于不可用状态: (1)验证:对加载的字节流进行验证,比如格式上的,安全方面的: (2)内存分配:为该类准备内存空间来表示其属性,方法以及引用的类: (3)解析:加载该类所引用的其它类,比如父类,实现的接口等. 3.初始化:对类变量进行赋值. 类加载器的

深入类加载器的理解偏差,请大家帮忙解释一下

问题描述 看到这样一句话:如果程序对线程上下文类加载器没有任何改动的话,程序中所有的线程将都使用系统类加载器作为上下文类加载器1.如果使用了系统类加载器,而系统类加载器的内部还是使用了委派的机制,这样如何说是抛弃了委派机制呢?2.当前类加载器,上下文类加载器,引导类加载器,扩展类加载器,系统类加载器,这些简单来说是怎样的关系呢?是不是前两者的内部其实还是后面三种来实现的? 解决方案 解决方案二: 解决方案三:建议楼主先看一遍---深入javajvm解决方案四:谢谢雅典娜建议,我这个就是在读深入虚

类加载器与单例

当使用不同的类加载器时,也会使单例失效,如下:  单例为:  ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public final class Singleton{           private static final Singleton instance=new Singleton();           private Singleton(){                 System.out.println("执行构造函数");      

JAVA加密解密:自定义类加载器应用

最近在研究JAVA CLASS LOADING技术,已实现了一个自定义的加载器.对目前自定义加载器的应用,还在探讨中.下面是自定义的CLASSLOADER在JAVA加密解密方面的一些研究. JAVA安全 JAVA是解释执行的语言,对于不同的操作平台都有相应的JVM对字节码文件进行解释执行.而这个字节码文件,也就是我们平时所看到的每一个.class文件. 这是我们大家都知道的常识,也就是由.java文件,经过编译器编译,变成JVM所能解释的.class文件. 而这个过程,在现在公开的网络技术中,利

深入探讨Java类加载器

类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一. 它使得 Java 类可以被动态加载到 Java 虚拟机中并执行.类加载器从 JDK 1.0 就出现了,最初是为了满足 Java Applet 的需要而开发出来的.Java Applet 需要从远程下载 Java 类文件到浏览器中并执行.现在类加载器在 Web 容器和 OSGi 中得到了广泛的使用.一般来说,Java 应用的开发人员不需要直接同类加 载器进行交互.Java 虚拟机默认的行为就已经足够满足大多数情况的需求