用户定制自己的ClassLoader能够实现以下的一些应用:

  1. 自己定义路径下查找自己定义的class类文件,或许我们须要的class文件并不总是在已经设置好的Classpath以下,那么我们必须想办法来找到这个类,在这样的清理下我们须要自己实现一个ClassLoader。

  2. 确保安全性:Java字节码非常easy被反编译,对我们自己的要载入的类做特殊处理,如保证通过网络传输的类的安全性。能够将类经过加密后再传输,在加密到JVM之前须要对类的字节码在解密。这个过程就能够在自己定义的ClassLoader中实现。

  3. 实现类的热部署:能够定义类的实现机制。假设我们能够检查已经载入的class文件是否被改动,假设改动了。能够又一次载入这个类。

  findClass()的功能是找到class文件并把字节码载入到内存中。自己定义的ClassLoader一般覆盖改方法。以便使用不同的载入路径,然后调用defineClass()解析字节码。

  defineClass()方法用来将byte字节流解析成JVM能够识别的Class对象。

有了这种方法意味着我们不仅仅能够通过class文件实例化对象。还能够通过其它方式实例化对象,如我们通过网络接收到一个类的字节码,拿这个字节码流直接创建类的Class对象形式实例化对象。

  自己定义的载入器能够覆盖方法loadClass()以便定义不同的载入机制。

  假设自己定义的载入器仅覆盖了findClass(),而未覆盖loadClass(即载入规则一样,但载入路径不同);则调用getClass().getClassLoader()返回的仍然是AppClassLoader!由于真正的load类,还是AppClassLoader.


载入自己定义路径下的class文件

  以下演示一个方法载入指定路径下(”D:/workspace_jee/JavaTest/src/”)的类文件。

package classloader;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream; public class PathClassLoader extends ClassLoader
{
private String classPath; public PathClassLoader(String classPath)
{
this.classPath = classPath;
} @Override
protected Class<? > findClass(String name) throws ClassNotFoundException
{
byte[] classData = getData(name);
if (classData == null)
{
throw new ClassNotFoundException();
}
else
{
return defineClass(name, classData, 0, classData.length);
}
} private byte[] getData(String className)
{
String path = classPath + File.separatorChar+className.replace('.', File.separatorChar)+".class";
try
{
InputStream is = new FileInputStream(path);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
byte[] buffer = new byte[2048];
int num = 0;
while((num = is.read(buffer))!=-1)
{
stream.write(buffer,0,num);
}
return stream.toByteArray();
}
catch(IOException e)
{
e.printStackTrace();
} return null;
} public static void main(String args[]) throws ClassNotFoundException, InstantiationException, IllegalAccessException
{
ClassLoader pcl = new PathClassLoader("D:/workspace_jee/JavaTest/src/");
Class c = pcl.loadClass("classloader.SingleClass");
System.out.println(c.newInstance());
}
}

  输出结果:classloader.SingleClass@22a7fdef


载入自己定义格式的class文件

  假设我们从网路上下载一个class文件的字节码,可是为了安全性在传输之前对这个字节码进行了简单的加密处理,然后再通过网络传输。

当client接收到这个类的字节码后须要经过解密才干还原成原始的类格式。然后再通过ClassLoader的defineClass()方法创建这个类的实例,最后完毕类的载入工作。

  比方上面的代码中,在获取到字节码(byte[] classData = getData(name);)之后再通过一个相似以下的代码:

    private byte[] deCode(byte[] src){
byte[] decode = null;
//do something niubility! 精密解码过程
return decode;
}

  将字节码解码成所须要的字节码就可以。


实现类的热部署

  JVM默认不能热部署类,由于载入类时会去调用findLoadedClass(),假设类已被载入,就不会再次载入。

  JVM推断类是否被载入有两个条件:完整类名是否一样,ClasssLoader是否是同一个

  所以要实现热部署的话,仅仅须要使用ClassLoader的不同实例来载入。

  假设用同一个ClassLoader实例来载入同一个类,则会抛出LinkageError.

  Jsp就是一个热部署的样例。

  例如以下所看到的:

package classloader;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream; public class ClassReloader extends ClassLoader
{
private String classPath;
String classname = "classloader.SingleClass"; public ClassReloader(String classpath)
{
this.classPath = classpath;
} protected Class<?> findClass(String name) throws ClassNotFoundException{
byte [] classData = getData(name);
if(classData == null)
{
throw new ClassNotFoundException();
}
else
{
return defineClass(classname,classData,0,classData.length);
}
} private byte[] getData(String className)
{
String path = classPath+className;
try
{
InputStream is = new FileInputStream(path);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
byte[] buffer = new byte[2048];
int num = 0;
while((num = is.read(buffer))!=-1)
{
stream.write(buffer,0,num);
}
return stream.toByteArray();
}
catch(IOException e)
{
e.printStackTrace();
}
return null;
} public static void main(String[] args)
{
try
{
String path = "D:/workspace_jee/JavaTest/src/classloader/";
ClassReloader reloader = new ClassReloader(path);
Class r = reloader.findClass("SingleClass.class");
System.out.println(r.newInstance());
// ClassReloader reloader2 = new ClassReloader(path);
Class r2 = reloader.findClass("SingleClass.class");
System.out.println(r2.newInstance());
}
catch (ClassNotFoundException | InstantiationException | IllegalAccessException e)
{
e.printStackTrace();
}
}
}

  这段代码的执行结果为:

 java.lang.LinkageError: loader (instance of  classloader/ClassReloader): attempted  duplicate class definition for name: "classloader/SingleClass"
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.lang.ClassLoader.defineClass(Unknown Source)
at classloader.ClassReloader.findClass(ClassReloader.java:26)
at classloader.ClassReloader.main(ClassReloader.java:62)

  比較两个类是否“相等”,仅仅有在这两个类是由同一个类载入器载入的前提下才有意义。否则。即使这两个类来源于同一个Class文件,被同一个虚拟机载入,仅仅要载入他们的类载入器不同,那这两个类就必然不相等。

Java类载入器(二)——自己定义类载入器的更多相关文章

  1. 疯狂java学习笔记之面向对象(一) - 定义类、方法、构造器

    Java面向对象 1.定义类 2.创建对象.调用方法 类和对象: 某一类对象的概念定义. 比如:人类 - 抽象出来的概念(不特指某个人) 对象 - 在类的概念下产生的一个实例,它就是一个对象了. ja ...

  2. Java 学习 第二篇;面向对象 定义类的简单语法:

    1:基本知识 [public / protected / private] class 类名 { 零个到多个构造器定义; 零个到多个属性; 零个到多个方法; } 其中类中各个成员之间的顺序没有关系,且 ...

  3. 转: 深入Java虚拟机】之二:Class类文件结构

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/17675609 平台无关性 Java是与平台无关的语言,这得益于Java源代码编译后生成的存 ...

  4. 【深入Java虚拟机】之二:Class类文件结构

    平台无关性 Java是与平台无关的语言,这得益于Java源代码编译后生成的存储字节码的文件,即Class文件,以及Java虚拟机的实现.不仅使用Java编译器可以把Java代码编译成存储字节码的Cla ...

  5. java基础(十二)常用类总结(二)

    这里有我之前上课总结的一些知识点以及代码大部分是老师讲的笔记 个人认为是非常好的,,也是比较经典的内容,真诚的希望这些对于那些想学习的人有所帮助! 由于代码是分模块的上传非常的不便.也比较多,讲的也是 ...

  6. Java初学者作业——完成对已定义类(Admin)的对象的创建。并完成属性的赋值和方法的调用。

    返回本章节 返回作业目录 需求说明: 完成对已定义类(Admin)的对象的创建.并完成属性的赋值和方法的调用. 实现思路: 创建 MyTest 类,并添加 main函数. 在 main函数中完成对 A ...

  7. 深入理解Java类加载器(二):线程上下文类加载器

    摘要: 博文<深入理解Java类加载器(一):Java类加载原理解析>提到的类加载器的双亲委派模型并不是一个强制性的约束模型,而是Java设计者推荐给开发者的类加载器的实现方式.在Java ...

  8. Java 网络编程(二) 两类传输协议:TCP UDP

    链接地址:http://www.cnblogs.com/mengdd/archive/2013/03/09/2951841.html 两类传输协议:TCP,UDP TCP TCP是Transfer C ...

  9. [python 基础]python装饰器(二)带参数的装饰器以及inspect.getcallargs分析

    带参数的装饰器理解无非记住两点: 1.本质不过在基本的装饰器外面再封装一层带参数的函数 2.在使用装饰器语法糖的时候与普通装饰器不同,必须要加()调用,且()内的内容可以省略(当省略时,admin默认 ...

随机推荐

  1. SVM 支持向量机算法介绍

    转自:https://zhuanlan.zhihu.com/p/21932911?refer=baina 参考:http://www.cnblogs.com/LeftNotEasy/archive/2 ...

  2. VisionPro显示隐藏搜索区域

    假如我们需要显示两张图,一张显示CogPMAlignTool工具不带搜索区域的,一张显示CogPMAlignTool工具带搜索区域的图像 VisionPro显示隐藏搜索区域 VisionPro显示隐藏 ...

  3. [转]构建Python+Selenium2自动化测试环境(二)

    构建Python+Selenium2自动化测试环境完成之后,就需要测试支持python的selenium的版本是否都支持在不同浏览器上运行,当前我们分别在三个最通用的浏览器上通过脚本来测试. 1.在I ...

  4. [android开发篇]权限列表

    http://www.open-open.com/lib/view/open1425868811607.html

  5. 利用ps,grep,kill联合杀掉相关进程

    #!/bin/sh . "./set-server-env.sh" 这里是输出ps -ef |grep java 结果的第二列的内容然后通过xargs传递给kill -9,其实第二 ...

  6. 两周多学完Java 23种设计模式

       最近两周任务不是很繁重,对于一个刚入职4个月的菜鸟来说,学习设计模式并灵活使用简直天方夜谭:但是当我询问我导师需要学点啥的时候?“<Java设计模式>,这个必须要学”,一句简单粗略的 ...

  7. BZOJ2561 最小生成树 【最小割】

    题目 给定一个边带正权的连通无向图G=(V,E),其中N=|V|,M=|E|,N个点从1到N依次编号,给定三个正整数u,v,和L (u≠v),假设现在加入一条边权为L的边(u,v),那么需要删掉最少多 ...

  8. 【数位DP】bnuoj 52813 J. Deciphering Oracles

    http://acm.bnu.edu.cn/v3/contest_show.php?cid=9208#problem/J [AC] #include<bits/stdc++.h> usin ...

  9. OsCache MemCached EhCache

    Memcache:分布式内存对象缓存系统,占用其他机子的内存.很多互联网,负载均衡三台(以三台为例)web服务器可以共享一台Memcache的资源.传递的信息以键值对的形式存储.传递的数据要实现序列化 ...

  10. spring中quartz的使用。【转http://www.cnblogs.com/kay/archive/2007/11/02/947372.html】

    注:从spring3到spring4改变 org.springframework.scheduling.quartz.CronTriggerBean org.springframework.sched ...