java中的.java文件经过编译以后,就会生成类文件.class文件。class文件是以二进制字节码存放在硬盘中的。当我们需要使用或加载Java文件到JVM中的时候,会从硬盘中读取字节码的class文件,然后通过类加载器将class文件加载到JVM中。也就是说,所有的Java文件都是通过类加载器加载到JVM中的。当然类加载器也是一个Java文件。那么第一个类加载器又是如何加载到JVM中的呢?在启动JVM的时候,会调运一个本地方法findBootStrapClass方法加载最初始的那个ClassLoader,private native Class findBootstrapClass(String name),这个本地方法使用C++编写的。
1.系统已有3种类加载器
1.1 BooststrapClassLoader(boot) 加载rt.jar下面的类(此加载器采用C++编写,一般开发中是看不到的)
1.2 ExtClassLoader 加载ExtClassLoader下面的类(ext文件夹下面的jar)
1.3 AppClassLoader 加载classpaht下面的类
我们写的类几乎都是通过AppClassLoader这个加载器加载到JVM中的。
2.类加载器的加载机制(双亲委托机制)
每一个类加载器都有一个对应的parentClassLoader。
2.1 系统类加载器的父子关系
自定义类加载器的父亲是AppClassLoader
AppClassLoader的父亲是ExtClassLoader
ExtClassLoader的父亲是BooststrapClassLoader
public class TestClassLoader { public static void main(String[] args) { // 当前对象的类加载器 ClassLoader loader = new TestClassLoader().getClass().getClassLoader(); // 从当前对象的类加载器想上找他的各个祖先 while (loader != null) { System.out.println(loader.getClass().getName()); loader = loader.getParent(); } // 知道找到最后的祖先是null System.out.println(loader); } } 输出: sun.misc.Launcher$AppClassLoader sun.misc.Launcher$ExtClassLoader null
2.2 类加载器加载的顺序
类加载器是从根向下加载的
也就是boot-》ExiClassLoader -》AppClassLoader
当一个类需要被加载的时候,首先是由AppClassLoader加载器将其传递给其父亲ExtClassLoader,然后ExtClassLoader再将其传递给他的父亲boot。
当boot发现他的加载范围内有对应的class,就加载到JVM中,否则交给儿子ExtClassLoader处理。
ExtClassLoader再在他的加载范围类找有没有对应的class,有就加载到JVM中,没有就交给AppClassLoader处理。
AppClassLoader再在classpath路径下找对应的class,找到就加载,没有就报异常。
原因:这样可以保证JVM中某一个className对应的是同一个class,因为都是从根向下加载的。
避免重复加载,当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次。
要是从下向上加载,可能导致某一个className在JVM中对应好几个class。可能我们会定义自己的类加载器和自己的加载范围。
当自己定义的类加载在他们各自的范围都发现需要加载的类,那么他们可能都会加载,导致JVM中一个className对应好几个不同的class
2.3 比如我们自己定义一个类加载器去加载java.lang.String这个类,那么我们是不能达到我们目的的。
因为加载机制是从上到下加载,当传递到上面的boot的时候,已经被加载到JVM中,轮不到我们自定义的类加载器去加载它。
但是,我们肯定是可以自己定义一个类加载器去加载我们指定的类的。
3.如何自定义一个类加载
首先,我们需要继承ClassLoadar
然后,我们不能破坏原来的类加载机制(双亲委托机制),所以我们不能覆盖loadClass方法,我们需要覆盖findclass方法。
最后,在findClass方法中写入我们的类加载器的代码。
查看源码解释:
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // 首先检查name对应的Class是否已经被加载 Class c = findLoadedClass(name); //如果没有被加载 if (c == null) { long t0 = System.nanoTime(); //尝试让parentClassLoader去加载 try { if (parent != null) { //当parent不为null的时候,让parent去loadClass c = parent.loadClass(name, false); } else { //当parent为null的时候,就调运本地方法 c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { } //当parentClassLoader没有加载的时候 if (c == null) { long t1 = System.nanoTime(); //调运findClass方法去加载 c = findClass(name); } } if (resolve) { resolveClass(c); } return c; } }
4.举例
目标:自定义一个类加载器加我们指定路径下,经过我么加密的class。
过程:找到指定路径下的class文件,解密,加载到JVM中。
4.1先定义一个需要被加密编译的类,同时使用它进行测试
public class MyClass extends Date { @Override public String toString() { return "hello world"; } }
4.2加密原来的class文件
public static void main(String[] args) throws Exception { String inputSrc = args[0];//原来的class文件的路径和文件名 String outputSrc = args[1];//加密以后存放的文件路径和文件名 FileInputStream fis = new FileInputStream(inputSrc); FileOutputStream fos = new FileOutputStream(outputSrc); //调用加密算法 cypher(fis, fos); fis.close(); fos.close(); } /** * 加密解密函数方法 * * @param is * @param os * @throws IOException */ private static void cypher(InputStream is, OutputStream os) throws IOException { int b = -1; while ((b = is.read()) != -1) { // 将0变成1,将1变成0 os.write(b ^ 0xff); } }
4.3编写我们自己的类加载器
public class MyClassLoader extends ClassLoader { //要加载的类的路径 private String classSrc; public MyClassLoader() { } public MyClassLoader(String classSrc) { this.classSrc = classSrc; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { //先找到自己的加密的class文件的位置 String classFielName = classSrc + "\\" + name + ".class"; try { FileInputStream fis = new FileInputStream(classFielName); ByteArrayOutputStream baos = new ByteArrayOutputStream(); //调运解密算法 cypher(fis, baos); fis.close(); byte[] bytes = baos.toByteArray(); //将读出来的二进制转换为Class字节码 return defineClass(null, bytes, 0, bytes.length); } catch (Exception e) { e.printStackTrace(); } return super.findClass(name); } }
4.4使用我们自己的类加载加载我们加密的类到JVM中
//首先使用自己的类加载器去加载我们加密的class文件 //注意,这个地方的加载类的路径下的class应该是我们加密以后文件的位置 Class clazz = new MyClassLoader("E:/AllWorkspace/workspace1/classLoaderTest/bin/com/gusi/test").loadClass("MyClass"); //通过反射,测试我们的classLoader Date date = (Date) clazz.newInstance(); System.out.println(date.toString());
相关推荐
Java中的类加载器(ClassLoader)是Java虚拟机(JVM)的一个重要组成部分,它负责将类的.class文件从文件系统或者网络中加载到内存中,并转换为对应的Class对象。类加载器的工作流程主要包括加载、验证、准备、解析...
类加载器(`ClassLoader`)是Java运行时环境的一部分,它的主要职责是从文件系统或网络中获取字节码,将其转换为`Class`对象,并在Java虚拟机中运行。Java中的类加载机制遵循“按需加载”原则,即只有当程序真正需要...
破解java加密的ClassLoader.java,在classloader植入破解代码
在Java编程语言中,ClassLoader是一个至关重要的组成部分,它负责加载类到JVM(Java虚拟机)中。理解ClassLoader的工作原理以及如何定制它,对于深入学习Java的运行机制和进行高级应用开发具有重要意义。本篇文章将...
Java ClassLoader是一个核心的Java运行时组件,负责加载类到Java虚拟机(JVM)中。它是Java平台的独特特性,因为它允许动态加载类,增强了软件的可扩展性和灵活性。这篇博文(虽然链接不可用)可能深入探讨了...
Java 中的 ClassLoader Java 中的 ClassLoader 是一个非常重要的组件,它负责动态加载 class 文件到虚拟机当中,并将其转换成 java.lang.Class 类的一个实例。每个这样的实例用来表示一个 Java 类,因此我们可以...
Java ClassLoader机制是Java虚拟机(JVM)中一个至关重要的组成部分,它的主要任务是将类的.class文件加载到JVM中,使得程序能够运行。ClassLoader不仅负责类的加载,还涉及类的验证、初始化等一系列过程。理解...
在Java编程语言中,ClassLoader是核心组件之一,它负责加载类到JVM(Java虚拟机)中。理解ClassLoader的工作机制以及类变量初始化的顺序对于深入理解Java运行时环境至关重要。这篇博文将探讨这两个主题。 首先,让...
本Demo程序主要探讨的是Java中的ClassLoader等级关系,这一主题对于理解Java应用程序的运行机制至关重要。 首先,我们要了解ClassLoader的基本概念。在Java中,ClassLoader是一个系统组件,它根据指定的全限定类名...
### Java ClassLoader原理详解 #### 摘要 本文探讨了Java虚拟机(JVM)中的一个重要特性:动态类加载(Dynamic Class Loading)。这一机制为Java平台提供了强大的能力,允许在运行时安装软件组件,例如从网络下载...
本文详细介绍了 Java 中的类加载器及其工作原理,包括类加载器的不同类型、类的加载过程以及类加载器与类实例化的关联。深入理解类加载机制对于开发高质量的 Java 应用程序至关重要,特别是在处理多层架构、模块化...
Java ClassLoader机制是Java运行时环境中的核心组件之一,它负责加载类到JVM(Java虚拟机)中,使得程序能够执行。理解ClassLoader的工作原理对于优化应用性能、处理类加载问题以及实现自定义加载器至关重要。 首先...
ClassLoader 是 Java 中的一个抽象类,它的主要作用是加载 Class 文件到 JVM 中。ClassLoader 使用了双亲委托模式进行类加载,每一个自定义的 ClassLoader 都必须继承 ClassLoader 这个抽象类,而每个 ClassLoader ...
让Java支持热加载是个不错的想法。如何做到的呢? 1. 定义好接口和实现类 2. 让代理类通过反射的方式调用实现类,对外暴露的是代理类。 3. 自定义URLClassLoader。检查实现类.class文件的...Java自定义classloader;
### Java虚拟机中ClassLoader概述与双亲委托机制详解 #### 一、ClassLoader概念与作用 在Java编程语言中,`ClassLoader`是一个非常重要的组件,它负责加载程序运行所需的类文件到Java虚拟机(JVM)中。`ClassLoader`...
在 Java 虚拟机(JVM)中,类加载器(ClassLoader)扮演着非常重要的角色。类加载器负责加载 Java 类,包括核心类和用户自定义类。在 JVM 运行过程中,类加载器会形成一个层次结构,包括引导类加载器(Bootstrap ...
为了更好地理解和利用Java的这一特性,本篇将详细介绍Java ClassLoader的作用及其工作原理,并通过构建一个示例ClassLoader来帮助读者深入理解如何自定义ClassLoader,从而扩展JVM的功能。 #### 二、ClassLoader...