博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java类载入器(二)——自己定义类载入器
阅读量:6647 次
发布时间:2019-06-25

本文共 5267 字,大约阅读时间需要 17 分钟。

  用户定制自己的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文件,被同一个虚拟机载入,仅仅要载入他们的类载入器不同,那这两个类就必然不相等。

转载地址:http://kluto.baihongyu.com/

你可能感兴趣的文章
AutoCompleteTextView的简单使用
查看>>
HDOJ_ACM_下沙的沙子有几粒?
查看>>
WP7 XAML介绍
查看>>
Node.js能让Javascript写后端,为啥不让Python写前端?
查看>>
陶哲轩实分析 习题 12.5.8 :度量空间中有界闭集不一定是紧集
查看>>
使用VS2012遇到的问题
查看>>
20.元素分类--内联块状元素
查看>>
出错。instantiating servlet class(无法实例化servlet)
查看>>
应该做什么样的研究:以Google为例
查看>>
Windows Phone 8.1 页面导航
查看>>
web前端工程师全套教程免费分享
查看>>
非对称加密相关基础
查看>>
Leetcode | Sum Root to Leaf Numbers
查看>>
在线求中位数
查看>>
Sql server在另一台服务器,在Visual Studio 中没问题,IIS中 提示“在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误。。。。”...
查看>>
Zookeeper
查看>>
linux 系统备份还原
查看>>
动态生成Menu
查看>>
插入排序
查看>>
JDBC的封装
查看>>