深入JVM类加载器(2)

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 深入JVM类加载器

文件类加载器

package com.lyy.test;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
 * 自定义文件系统加载器
 * @author 01
 *
 */
public class FileSystemClassLoader extends ClassLoader{
    //com.lyy.test.User --> d:/myjava/com/lyy/test/User.class
    private String rootDir;
    public FileSystemClassLoader(String rootDir){
        this.rootDir=rootDir;
    }
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class<?> c = findLoadedClass(name);
        //首先查询是否加载过该类,如果已经加载过,直接返回已经加载好的类,否则加载新的类
        if(null != c){
            return c;
        }else{
            ClassLoader parent = this.getParent();
            c = parent.loadClass(name); //委派给父类加载
            if(null != c){
                return c;
            }else{
                byte[] classData = getClassData(name);
                if(classData==null){
                    throw new ClassNotFoundException();
                }else{
                    c = defineClass(name, classData,0, classData.length);
                }
            }
        }
        return c;
    }
    private byte[] getClassData(String name) {  //com.lyy.test.User    d:/myjava/com/lyy/test/User.class
        String path = rootDir+"/"+name.replace('.', '/')+"class";
        //IOUtils,可以使用它将流中的数据转成字节数据
        InputStream is = null;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            is = new FileInputStream(path);
            byte[] buffer = new byte[1024];
            int temp = 0;
            while((temp=is.read(buffer)) != -1){
                baos.write(buffer,0,temp);
            }
            return baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }finally{
            try {
                if(is != null){
                    is.close();
                }
                if(baos != null){
                    baos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}


网络类加载器

package com.lyy.test;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
/**
 * 网络类加载器
 * @author 01
 *
 */
public class NetClassLoader extends ClassLoader{
    //com.lyy.test.User --> www.baidu.com
    private String rootUrl;
    public NetClassLoader(String rootUrl){
        this.rootUrl=rootUrl;
    }
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class<?> c = findLoadedClass(name);
        //首先查询是否加载过该类,如果已经加载过,直接返回已经加载好的类,否则加载新的类
        if(null != c){
            return c;
        }else{
            ClassLoader parent = this.getParent();
            c = parent.loadClass(name); //委派给父类加载
            if(null != c){
                return c;
            }else{
                byte[] classData = getClassData(name);
                if(classData==null){
                    throw new ClassNotFoundException();
                }else{
                    c = defineClass(name, classData,0, classData.length);
                }
            }
        }
        return c;
    }
    private byte[] getClassData(String name) {  //com.lyy.test.User    d:/myjava/com/lyy/test/User.class
        String path = rootUrl+"/"+name.replace('.', '/')+"class";
        //IOUtils,可以使用它将流中的数据转成字节数据
        InputStream is = null;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            URL url = new URL(path);
            is = url.openStream();
            byte[] buffer = new byte[1024];
            int temp = 0;
            while((temp=is.read(buffer)) != -1){
                baos.write(buffer,0,temp);
            }
            return baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }finally{
            try {
                if(is != null){
                    is.close();
                }
                if(baos != null){
                    baos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}


加密解密加载器(取反操作,DES对称加密解密)

package com.lyy.test;
/**
 * 测试简单加密解密(取反)操作
 * @author 01
 *
 */
public class Demo4 {
    public static void main(String[] args) throws Exception {
        //测试取反操作
//      int a = 3;//0000011
//      System.out.println(Integer.toBinaryString(a^0xff));
        //加密后的class文件,正常的类加载器无法加载,报clasformatError
//      FileSystemClassLoader load = new FileSystemClassLoader("E:/VIP/temp");
//      Class<?> c = load.loadClass("HelloWrold");
//      System.out.println(c);
        DecrptClassLoader loader = new DecrptClassLoader("E:/VIP/temp");
        Class<?> c = loader.loadClass("com.lyy.temp.HelloWrold");
        System.out.println(c);
    }
}
package com.lyy.test;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
 * 自定义文件系统加载器
 * @author 01
 *
 */
public class FileSystemClassLoader extends ClassLoader{
    //com.lyy.test.User --> d:/myjava/com/lyy/test/User.class
    private String rootDir;
    public FileSystemClassLoader(String rootDir){
        this.rootDir=rootDir;
    }
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class<?> c = findLoadedClass(name);
        //首先查询是否加载过该类,如果已经加载过,直接返回已经加载好的类,否则加载新的类
        if(null != c){
            return c;
        }else{
            ClassLoader parent = this.getParent();
            c = parent.loadClass(name); //委派给父类加载
            if(null != c){
                return c;
            }else{
                byte[] classData = getClassData(name);
                if(classData==null){
                    throw new ClassNotFoundException();
                }else{
                    c = defineClass(name, classData,0, classData.length);
                }
            }
        }
        return c;
    }
    private byte[] getClassData(String name) {  //com.lyy.test.User    d:/myjava/com/lyy/test/User.class
        String path = rootDir+"/"+name.replace('.', '/')+"class";
        //IOUtils,可以使用它将流中的数据转成字节数据
        InputStream is = null;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            is = new FileInputStream(path);
            byte[] buffer = new byte[1024];
            int temp = 0;
            while((temp=is.read(buffer)) != -1){
                baos.write(buffer,0,temp);
            }
            return baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }finally{
            try {
                if(is != null){
                    is.close();
                }
                if(baos != null){
                    baos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
package com.lyy.test;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
 * 加载文件系统加密后的class字节码的类加载器
 * @author 01
 *
 */
public class DecrptClassLoader extends ClassLoader{
    //com.lyy.test.User --> d:/myjava/com/lyy/test/User.class
    private String rootDir;
    public DecrptClassLoader(String rootDir){
        this.rootDir=rootDir;
    }
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class<?> c = findLoadedClass(name);
        //首先查询是否加载过该类,如果已经加载过,直接返回已经加载好的类,否则加载新的类
        if(null != c){
            return c;
        }else{
            ClassLoader parent = this.getParent();
            c = parent.loadClass(name); //委派给父类加载
            if(null != c){
                return c;
            }else{
                byte[] classData = getClassData(name);
                if(classData==null){
                    throw new ClassNotFoundException();
                }else{
                    c = defineClass(name, classData,0, classData.length);
                }
            }
        }
        return c;
    }
    private byte[] getClassData(String name) {  //com.lyy.test.User    d:/myjava/com/lyy/test/User.class
        String path = rootDir+"/"+name.replace('.', '/')+"class";
        //IOUtils,可以使用它将流中的数据转成字节数据
        InputStream is = null;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            is = new FileInputStream(path);
            int temp = -1;
            while((temp=is.read()) != -1){
                baos.write(temp^0xff); //取反操作,相当于解密操作
            }
            return baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }finally{
            try {
                if(is != null){
                    is.close();
                }
                if(baos != null){
                    baos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

线程上下文类加载器

双亲委托机制以及类加载器的问题

一般情况下,保证同一个类中所关联的其他类都是由当前类的类加载器所加载的。

比如,Class本身在Ext下找到,那么他里面new出来的一些类也就只能用ext去查找了(不会低一个级别),所以有些明明app可以找到的,却找不到了。

JDBC API 他有实习那的driven部门(mysql/sql server),我们的JDBC API都是由Boot或者Ext来载入的,但是Service Prover却是由EXT或者App来载入,那么就有可能找不到driver了,在java领域中,其实只要分成这种Api-SPI(Service Provide Interface,特定厂商提供)的,都会遇到此问题。

常见的SPi 有JDBC、JCE、JNXP和JBI等。

package com.lyy.test;
/**
 * 线程上下文类加载器
 * @author 01
 *
 */
public class Demo5 {
    public static void main(String[] args) throws Exception {
        ClassLoader loader = Demo5.class.getClassLoader();
        System.out.println(loader);
        ClassLoader laoder2 = Thread.currentThread().getContextClassLoader();
        System.out.println(laoder2);
        Thread.currentThread().setContextClassLoader(new FileSystemClassLoader("E:/VIP/"));
        System.out.println(Thread.currentThread().getContextClassLoader());
        Class<Demo1> c = (Class<Demo1>)Thread.currentThread().getContextClassLoader().loadClass("com.lyy.test.Demo1");
        System.out.println(c);
        System.out.println(c.getClassLoader());
    }
}

屏幕快照 2022-05-10 上午11.44.47.png

目录
相关文章
|
4月前
|
安全 前端开发 Java
【JVM的秘密揭秘】深入理解类加载器与双亲委派机制的奥秘!
【8月更文挑战第25天】在Java技术栈中,深入理解JVM类加载机制及其双亲委派模型是至关重要的。JVM类加载器作为运行时系统的关键组件,负责将字节码文件加载至内存并转换为可执行的数据结构。其采用层级结构,包括引导、扩展、应用及用户自定义类加载器,通过双亲委派机制协同工作,确保Java核心库的安全性与稳定性。本文通过解析类加载器的分类、双亲委派机制原理及示例代码,帮助读者全面掌握这一核心概念,为开发更安全高效的Java应用程序奠定基础。
98 0
|
3月前
|
安全 Java 应用服务中间件
JVM常见面试题(三):类加载器,双亲委派模型,类装载的执行过程
什么是类加载器,类加载器有哪些;什么是双亲委派模型,JVM为什么采用双亲委派机制,打破双亲委派机制;类装载的执行过程
106 35
JVM常见面试题(三):类加载器,双亲委派模型,类装载的执行过程
|
2月前
|
缓存 前端开发 Java
JVM知识体系学习二:ClassLoader 类加载器、类加载器层次、类过载过程之双亲委派机制、类加载范围、自定义类加载器、编译器、懒加载模式、打破双亲委派机制
这篇文章详细介绍了JVM中ClassLoader的工作原理,包括类加载器的层次结构、双亲委派机制、类加载过程、自定义类加载器的实现,以及如何打破双亲委派机制来实现热部署等功能。
68 3
|
3月前
|
Arthas Java 测试技术
JVM —— 类加载器的分类,双亲委派机制
类加载器的分类,双亲委派机制:启动类加载器、扩展类加载器、应用程序类加载器、自定义类加载器;JDK8及之前的版本,JDK9之后的版本;什么是双亲委派模型,双亲委派模型的作用,如何打破双亲委派机制
JVM —— 类加载器的分类,双亲委派机制
|
2月前
|
前端开发 Java 应用服务中间件
JVM进阶调优系列(1)类加载器原理一文讲透
本文详细介绍了JVM类加载机制。首先解释了类加载器的概念及其工作原理,接着阐述了四种类型的类加载器:启动类加载器、扩展类加载器、应用类加载器及用户自定义类加载器。文中重点讲解了双亲委派机制,包括其优点和缺点,并探讨了打破这一机制的方法。最后,通过Tomcat的实际应用示例,展示了如何通过自定义类加载器打破双亲委派机制,实现应用间的隔离。
|
7月前
|
前端开发 安全 Java
深入浅出JVM(八)之类加载器
深入浅出JVM(八)之类加载器
|
4月前
|
数据库 C# 开发者
WPF开发者必读:揭秘ADO.NET与Entity Framework数据库交互秘籍,轻松实现企业级应用!
【8月更文挑战第31天】在现代软件开发中,WPF 与数据库的交互对于构建企业级应用至关重要。本文介绍了如何利用 ADO.NET 和 Entity Framework 在 WPF 应用中访问和操作数据库。ADO.NET 是 .NET Framework 中用于访问各类数据库(如 SQL Server、MySQL 等)的类库;Entity Framework 则是一种 ORM 框架,支持面向对象的数据操作。文章通过示例展示了如何在 WPF 应用中集成这两种技术,提高开发效率。
69 0
|
4月前
|
开发者 C# Windows
WPF布局大揭秘:掌握布局技巧,轻松创建响应式用户界面,让你的应用程序更上一层楼!
【8月更文挑战第31天】在现代软件开发中,响应式用户界面至关重要。WPF(Windows Presentation Foundation)作为.NET框架的一部分,提供了丰富的布局控件和机制,便于创建可自动调整的UI。本文介绍WPF布局的基础概念与实现方法,包括`StackPanel`、`DockPanel`、`Grid`等控件的使用,并通过示例代码展示如何构建响应式布局。了解这些技巧有助于开发者优化用户体验,适应不同设备和屏幕尺寸。
126 0
|
4月前
|
安全 前端开发 Java
【JVM 探秘】ClassLoader 类加载器:揭秘 Java 类加载机制背后的秘密武器!
【8月更文挑战第25天】本文全面介绍了Java虚拟机(JVM)中的类加载器,它是JVM的核心组件之一,负责将Java类加载到运行环境中。文章首先概述了类加载器的基本工作原理及其遵循的双亲委派模型,确保了核心类库的安全与稳定。接着详细阐述了启动、扩展和应用三种主要类加载器的层次结构。并通过一个自定义类加载器的例子展示了如何从特定目录加载类。此外,还介绍了类加载器的完整生命周期,包括加载、链接和初始化三个阶段。最后强调了类加载器在版本隔离、安全性和灵活性方面的重要作用。深入理解类加载器对于掌握JVM内部机制至关重要。
179 0
|
5月前
|
存储 前端开发 Java
(二)JVM成神路之剖析Java类加载子系统、双亲委派机制及线程上下文类加载器
上篇《初识Java虚拟机》文章中曾提及到:我们所编写的Java代码经过编译之后,会生成对应的class字节码文件,而在程序启动时会通过类加载子系统将这些字节码文件先装载进内存,然后再交由执行引擎执行。本文中则会对Java虚拟机的类加载机制以及执行引擎进行全面分析。
103 0