1.类加载器及委托机制的深入分析

  > 类加载器的作用:一个java文件中的出现的类,首先要把这个类的字节码加载到内存中,这个类的信息放在硬盘的classPath下的class文件中,

    把class文件中的内容加载到内存中去,在进行一些处理,处理完的结果就是字节码,这一系列工作是类加载器在做。

  > Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:

      BootStrap,ExtClassLoader, AppClassLoader

  > 类加载器也是Java类,因为其他是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是java类,

   这正是BootStrap

   BootStrap 很特殊,不是一个java类,是嵌套在jvm内核里的,jvm内核一启动BootStrap就已经在那里边了,BootStrap是由C++语言写的一段二进制代码,可以去加载别的类,包括别的类加载器

    System类是由BootStrap类加载器加载

用eclipse 的打包工具将ClassLoaderTest 输出成jre/lib/ext 目录下的itcast.jar包,再在eclipse中运行这个类,运行结果显示为ExtClassLoader。此时的环境状态时classpath目录有ClassLoaderTest.class, ext/itcast.jar 包中也有ClassLoaderTest.class。

当ExtClassLoader中能找到时,使用的是ExtClassLoader,当ExtClassLoader中找不到时,会去AppClassLoader中找,这里的原理是类加载器的委托机制。

public static void main(String[] args) {
System.out.println(ClassLoaderTest.class.getClassLoader().getClass()
.getName()); //sun.misc.Launcher$AppClassLoader /**
* System 的类加载器为null 不代表没有类加载器,代表是由一个特殊的类加载器加载 BootStrap类加载器
* 因为是嵌套在jvm里的,用java获取肯定获取不到,所有为null
*/
System.out.println(System.class.getClassLoader()); //null /**
* 以下程序打印
* sun.misc.Launcher$AppClassLoader
sun.misc.Launcher$ExtClassLoader
null
*/
ClassLoader loader = ClassLoaderTest.class.getClassLoader();
while(loader != null){
System.out.println(loader.getClass().getName());
loader = loader.getParent();
}
System.out.println(loader);
}

sun.misc.Launcher$ExtClassLoader

2.类加载器的委托机制

  2.1.可以定义类加载器,自定义类加载器需要继承ClassLoader,自定义的类加载器可以指定一个特定的目录

  2.2 当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?

    > 首先当前线程的类加载器去加载线程中的第一个类。getContextClassLoader() setContextClassLoader(ClassLoader cl)

    > 如果类A 中引用了类B ,Java虚拟机将使用加载类A的类加载器来加载类B。

    > 还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。

  2.3 每个类加载器加载类时,又先委托给其上级加载器。

    > 当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFoundException,

      不是再去找发起者类加载器的儿子,因为没有getChild方法,即使有,那有多少个儿子呢,找哪一个呢?

    > 对着类加载器的层次结构图和委托加载原理,解释先前将ClassLoaderTest输出成jar/lib/ext 目录下

      的itcast.jar包中后,运行结果为ExtClassLoader的原因

  2.4 模板方法设计模式

    父类 -->loadClass/findClass

      |----子类1(自己干)

      |----子类2(自己干)

    每个子类都有自己的方法逻辑,每个子类加载时都会去找其父节点,这个流程每个子类都会有,所以这个代码放在父类中

    我们要覆盖的是findClass,如果覆盖loadClass就会破坏这个流程

    得到class文件的转换成字节码 --> definedClass()

    

protected Class<?> defineClass(String name, byte[] b, int off, int len)

  Api中的一段代码:

The network class loader subclass must define the methods findClass and loadClassData to load a class from the network. Once it has downloaded the bytes that make up the class, it should use the method defineClass to create a class instance. A sample implementation is: 

     class NetworkClassLoader extends ClassLoader {
String host;
int port; public Class findClass(String name) {
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
} private byte[] loadClassData(String name) {
// load the class data from the connection
. . .
}
}

编写对class文件进行加密的工具类

  

public class MyclassLoader {

    public static void main(String[] args) throws Exception {
String srcPath = args[0];
String destDir = args[1];
FileInputStream fis = new FileInputStream(srcPath);
String destFileName = srcPath.substring(srcPath.lastIndexOf('\\')+1);
String destPath = destDir + "\\" + destFileName;
FileOutputStream fos = new FileOutputStream(destPath);
cypher(fis, fos);
fos.close();
fis.close();
} /**
* 加密
* @param is
* @param ot
* @throws IOException
*/
private static void cypher(InputStream is,OutputStream ot) throws IOException{
int b = -1;
while((b = is.read()) != -1){
ot.write(b ^ 0xff); //异或 0变1 1变0
}
}
}

在工程目录下新建一个文件夹 itcastlib

点击鼠标右键-> Run Configuration  填入运行参数

运行后,在文件夹itcastlib中新增一个class文件

  有包名的类不能调用无包名的类

  使用正常的class文件能够正常打印

  System.out.println(new ClassLoaderAttachment().toString());

  使用加密后的class文件替换正常的没有加密的class文件,并打印toString()

  则会抛出异常

 必须用自定义的类加载器,对加密的class可以进行解密的操作

private String classDir;

    @Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String classFileName = classDir + "\\" + name + ".class";
try {
FileInputStream fis = new FileInputStream(classFileName);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
cypher(fis, bos);
fis.close();
byte[] bytes = bos.toByteArray();
return defineClass(bytes, 0, bytes.length);
} catch (Exception e) {
}
return null;
} public MyclassLoader(String classDir){
this.classDir = classDir;
}

Class clazz = new MyclassLoader("itcastlib").loadClass("ClassLoaderAttachment");
Date d1 = (Date)clazz.newInstance(); //ClassLoaderAttachment这个类不能显示出现,因为这个类还是乱的
System.out.println(d1); //hello,itcast 解密成功

java高新技术-类加载器的更多相关文章

  1. java自定义类加载器

    前言 java反射,最常用的Class.forName()方法.做毕设的时候,接收到代码字符串,通过 JavaCompiler将代码字符串生成A.class文件(存放在classpath下,也就是ec ...

  2. Java虚拟机类加载器及双亲委派机制

    所谓的类加载器(Class Loader)就是加载Java类到Java虚拟机中的,前面<面试官,不要再问我"Java虚拟机类加载机制"了>中已经介绍了具体加载class ...

  3. 深入探讨java的类加载器

    类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一.它使得 Java 类可以被动态加载到 Java 虚拟机中并执行.类加载器从 JDK 1.0 就出现了,最初是为了满足 Ja ...

  4. java 中类加载器

    jar 运行过程和类加载机制有关,而类加载机制又和我们自定义的类加载器有关,现在我们先来了解一下双亲委派模式. java 中类加载器分为三个: BootstrapClassLoader 负责加载 ${ ...

  5. 深入理解Java虚拟机 - 类加载器

    引子:       类加载器(classloader)是独立于虚拟机之外,可以独立实现的代码模块.     OSGi使用了类加载器的这一特点实现其热插拔的特性       Java同C++等语言不通, ...

  6. 分析Java的类加载器与ClassLoader(二):classpath与查找类字节码的顺序,分析ExtClassLoader与AppClassLoader的源码

    先回顾一下classpath classpath的作用: classpath的作用是指定查找类的路径:当使用java命令执行一个类(类中的main方法)时,会从classpath中进行查找这个类. 指 ...

  7. java面向对象--类加载器及Class对象

    类加载器 jvm 和 类的关系 当调用 java命令运行一个java程序时,会启动一个java虚拟机进程.同一个jvm的所有线程.所有变量都处于同一个进程里,都使用该jvm进程的内存区. jvm进程终 ...

  8. Java的类加载器

    一.类加载器的概念 类加载器(class loader)用来加载 Java 类到 Java 虚拟机中.一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 ...

  9. Java的类加载器种类(双亲委派)

    Java类加载器采用双亲委派模型: 1.启动类加载器:这个类加载器负责放在<JAVA_HOME>\lib目录中的,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别 ...

随机推荐

  1. ASP.NET CORE 1.0 MVC API 文档用 SWASHBUCKLE SWAGGER实现

    from:https://damienbod.com/2015/12/13/asp-net-5-mvc-6-api-documentation-using-swagger/ 代码生成工具: https ...

  2. WIN7下强制分第四个主分区的方法

    通过磁盘管理的界面方式, 第四个分区会被分成扩展分区, 建议通过命令行 打开命令行运行diskpart, list disk 会列出所有磁盘, 选择要操作的磁盘序号如1,select disk 1 如 ...

  3. SQL Server 2005、2008 的 datetime 值范围(转)

    SQL Server 2005.2008 的 datetime 最小值是:1753-01-01 00:00:00 最大值是:9999-12-31 23:59:59.997 这与 .NET 中的 Dat ...

  4. R统计分析处理

    [翻译]Awesome R资源大全中文版来了,全球最火的R工具包一网打尽,超过300+工具,还在等什么? 阅读目录 0.前言 1.集成开发环境 2.语法 3.数据操作 4.图形显示 5.HTML部件 ...

  5. Python之线程、进程和协程

    python之线程.进程和协程 目录: 引言 一.线程 1.1 普通的多线程 1.2 自定义线程类 1.3 线程锁 1.3.1 未使用锁 1.3.2 普通锁Lock和RLock 1.3.3 信号量(S ...

  6. 一道int与二进制加减题

    int dis_data = 32769; if( dis_data > 0x7fff)  dis_data -= 0xffff; printf("%d\n",dis_dat ...

  7. 网页中三角切边还半透明,现在的设计师越来越牛,css也要跟上啊

    需求 今天在群里看到一个需求,啊这种三角形缺角怎么做啊,还带半透明阴影的. 分析 要实现这个,可以用css做三角,网上找一下代码,像这样. 由于以前没有试过border能不能带透明,所以需要试验一下. ...

  8. 如何拿到半数面试公司Offer——我的Python求职之路

    从八月底开始找工作,短短的一星期多一些,面试了9家公司,拿到5份Offer,可能是因为我所面试的公司都是些创业性的公司吧,不过还是感触良多,因为学习Python的时间还很短,没想到还算比较容易的找到了 ...

  9. 项目分享二:APP 小红点中数字的处理

    小红点,是 APP 中最常见的一个功能,我们先来看一下面的案例,下图中,待评价的商品有 2 个,点击“评价晒单”按钮进行评价后,那么待评价数量应该变成 1,那么这个功能是如何去实现的呢? 一般来说,实 ...

  10. OS存储器管理(一)

    存储器的层次: 分为寄存器.主存(内存)和 辅存(外存)三个层次. 主存:高速缓冲存储器.主存储器.磁盘缓冲存储器, 主存又称为可执行存储器: 辅存:固定磁盘存储器.可移动的外部存储器: 其可长期保存 ...