欢迎支持笔者新作:《深入理解Kafka:核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客。


欢迎跳转到本文的原文链接:https://honeypps.com/java/java-class-loading-2/

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

  1. 自定义路径下查找自定义的class类文件,也许我们需要的class文件并不总是在已经设置好的Classpath下面,那么我们必须想办法来找到这个类,在这种清理下我们需要自己实现一个ClassLoader。
  2. 确保安全性:Java字节码很容易被反编译,对我们自己的要加载的类做特殊处理,如保证通过网络传输的类的安全性,可以将类经过加密后再传输,在加密到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;}@Overrideprotected 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文件的字节码,但是为了安全性在传输之前对这个字节码进行了简单的加密处理,然后再通过网络传输。当客户端接收到这个类的字节码后需要经过解密才能还原成原始的类格式,然后再通过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文件,被同一个虚拟机加载,只要加载他们的类加载器不同,那这两个类就必定不相等。

欢迎跳转到本文的原文链接:https://honeypps.com/java/java-class-loading-2/

欢迎支持笔者新作:《深入理解Kafka:核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客。


Java类加载器(二)——自定义类加载器相关推荐

  1. jvm十二:自定义类加载器

    package com.atChina.jvm;import java.io.*;public class Test16 extends ClassLoader{private String clas ...

  2. Elasticsearch7 分词器(内置分词器和自定义分词器)

    文章目录 Elasticsearch7 分词器(内置分词器和自定义分词器) analysis 概览 char_filter html_strip mapping pattern_replace fil ...

  3. WebServices中使用cxf开发日志拦截器以及自定义拦截器

    首先下载一个cxf实例,里面包含cxf的jar包.我下的是apache-cxf-2.5.9 1.为什么要设置拦截器? 为了在webservice请求过程中,能动态操作请求和响应数据, CXF设计了拦截 ...

  4. Elasticsearch 分布式搜索引擎 -- 自动补全(拼音分词器、自定义分词器、自动补全查询、实现搜索框自动补全)

    文章目录 1. 自动补全 1.1 拼音分词器 1.2.1 自定义分词器 1.2.2 小结 1.2 自动补全 1.3 实现酒店搜索框自动补全 1.3.1 修改酒店映射结构 1.3.2 修改HotelDo ...

  5. 59、Docker ElasticSearch安装拼音分词器及自定义分词器

    一.使用拼音分词器 1.拼音分词器 2.docker下安装拼音分词器插件 3.测试拼音分词器 # 测试拼音分词器 POST /_analyze {   "text": [" ...

  6. flume拦截器及自定义拦截器

    拦截器做什么呢? 时间拦截器 以时间拦截器为例.会在Event的header中添加一个属性进去,属性的key叫做timestamp, value是当前的毫秒值. 问题是写到header然后呢?有啥用呢 ...

  7. ElasticSearch入门:ES分词器与自定义分词器

    ES入门:ES分词器与自定义分词器 分词器的简单介绍 不同分词器的效果对比 自定义分词器的应用 分词器的简单介绍 分词器是es中的一个组件,通俗意义上理解,就是将一段文本按照一定的逻辑,分析成多个词语 ...

  8. java 自定义类加载器_Java-JVM 自定义类加载器

    一.sun.misc.Launcher (ExtClassLoader 与 AppClassLoader 的创建) publicLauncher() { Launcher.ExtClassLoader ...

  9. Java类加载器及自定义类加载器

    一.类加载器父亲委托机制 Java类加载器采用父亲委托机制,先尝试用父加载器加载,父加载器无法加载,则此加载器加载, 注意,此父加载器与子加载器并非继承关系,而是指定的关系. 从ClassLoader ...

最新文章

  1. 新视界,你好!_只愿与一人十指紧扣_新浪博客
  2. 使用NMAKE管理工程
  3. [渝粤教育] 西南科技大学 高级英语(2) 在线考试复习资料
  4. 2013 822 划分子网
  5. cobol_在尝试之前不要讨厌COBOL
  6. 爬虫python是干什么的_爬虫是什么?能自学嘛
  7. layui 解决浏览器自动填充form表单账号和密码输入框的问题
  8. 7-15 求组合数 (15 分)
  9. c# datagridview列形式为Combobox,每行下拉选项不一样
  10. 百度开源深度学习框架【飞桨——PaddlePaddle】学习实践一
  11. LCD1602芯片的使用——简单易懂
  12. wps excel 向下选中指定行数并填充根据公式计算好的数据
  13. 基向量、非基向量、基解(基本解)、可行解、基本可行解、最优解
  14. 经典怀旧FCgame红白机小游戏在线网页合集版畅玩HTML网站源码
  15. KANZI入门第一篇之kanzi详解,教你轻松学kanzi
  16. 引起内存不能“read”的原因及“written”的解决方案
  17. python登录微信pc版_腾讯TIM iOS版2.5.6重大更新:新增支持微信帐号登录、语音进度条...
  18. python邮件发送
  19. Fast Fourier transform快速傅里叶变换
  20. (转)银河麒麟V10sp1服务器系统安装redis不能使用的解决办法

热门文章

  1. Shell多线程实现
  2. BugkuCTF web2
  3. AI看脸、测肤,左可美妆新零售,右能智慧医美
  4. 如何取消 DiscuzX 帖子被系统自动隐?
  5. 苹果推送消息服务(转)
  6. MFC程序崩溃的友好处理
  7. CodeForces - 1355C Count Triangles(数学)
  8. CodeForces - 1249C2 Good Numbers (hard version)(进制转换)
  9. CodeForces - 1208E Let Them Slide(模拟+multiset)
  10. HDU - 5978 To begin or not to begin(简单博弈)