Java_动态重新加载Class机制
Java动态重新加载Class
项目中使用到了动态重新加载Class的机制,作用是让一些代码上线之前可以在线上环境测试一下,当然,这是非常不好的测试机制,我刚来的时候也为这种机制感到惊讶—怎么可以在线上环境运行测试代码!后来经过了解,这么做的原因有以下两个:
- 有些代码没有办法在本地进行测试,本地没有线上的环境
- 我们弱到连测试机都没有(这是重点)
既然我们连测试机都没有,那么我就觉得我们的项目其实也没有想象中的重要,这么测就这么测吧~~
之前对ClassLoader没啥概念,google到一篇文章,翻译了一下并且做了一些补充,加深记忆
原文地址:
---------------------------------------------------
ClassLoader
顾名思义,ClassLoader就是用来Load Class的,当一个Class被加载的时候,这个Class所引用到的所有Class也会被加载,而且这种加载是递归的,也就是说,如果A引用到B,B 引用到C,那么当A被加载的时候,B也会被加载,而B被加载的时候,C也会加载。如此递归直到所有需要的Class都加载好。
常见的ClassLoader:
* Extension class loader:负责加载ext目录下的Class。
* Application class loader:负责加载CLASSPATH上的类。
ClassLoader的代理层次关系
ClassLoader是以层次关系组织起来的,当你创建一个标准的Java ClassLoader的时候,你必须提供一个父ClassLoader。当一个ClassLoader需要加载一个Class的时候,它首先会让父 ClassLoader去加载这个Class,如果父ClassLoader不能加载这个Class,那么当前的ClassLoader才会自己去加载。
ClassLoader加载Class的步骤:
- 检查这个Class是否已经被加载过了
- 如果没有被加载过,那么让父ClassLoader尝试去加载
- 如果父ClassLoader无法加载,那么尝试使用当前ClassLoader加载
从ClassLoader加载Class的步骤可以得知,如果你需要动态重新加载一个Class,那么你的ClassLoader必须跟上述标准流程有所区别,需要动态加载的Class不能交给父ClassLoader,否则你自己的ClassLoader将没有机会去加载这个Class(因为正常情况下父ClassLoader总是能加载到你所请求的Class)。
所以,如果你需要ClassLoader重新加载一个Class,重写findClass方法是起不到效果的,因为findClass在父 ClassLoader加载失败之后才会执行
- // First, check if the class has already been loaded
- Class c = findLoadedClass(name);
- if (c == null) {
- try {
- if (parent != null) {
- c = parent.loadClass(name, false);
- } else {
- c = findBootstrapClass0(name);
- }
- } catch (ClassNotFoundException e) {
- // If still not found, then invoke findClass in order
- // to find the class.
- c = findClass(name);
- }
- }
必须重写loadClass方法才能达到效果。
动态重新加载Class
Java内置的ClassLoader总会在加载一个Class之前检查这个Class是否已经被加载过,已经被加载过的Class不会加载第二次。因此要想重新加载Class,我们需要实现自己的ClassLoader。
另外一个问题是,每个被加载的Class都需要被链接(link),这是通过执行ClassLoader.resolve()来实现的,这个方法是 final的,因此无法重写。Resove()方法不允许一个ClassLoader实例link一个Class两次,因此,当你需要重新加载一个 Class的时候,你需要重新New一个你自己的ClassLoader实例。
刚才说到一个Class不能被一个ClassLoader实例加载两次,但是可以被不同的ClassLoader实例加载,这会带来新的问题:
- MyObject object = (MyObject)
- myClassReloadingFactory.newInstance("com.jenkov.MyObject");
这段代码会导致一个ClassCastException,因为在一个Java应用中,Class是根据它的全名(包名+类名)和加载它的 ClassLoader来唯一标识的。在上面的代码中object对象对应的Class和newInstance返回的实例对应的Class是有区别的:
| 全名 | ClassLoader实例 | |
| Object对象的Class | com.jenkov.MyObject | AppClassLoader实例 |
| newInstance返回对象的Class | com.jenkov.MyObject | 自定义ClassLoader实例 |
解决的办法是使用接口或者父类,只重新加载实现类或者子类即可。
- MyObjectInterface object = (MyObjectInterface)
- myClassReloadingFactory.newInstance("com.jenkov.MyObject");
- MyObjectSuperclass object = ( MyObjectSuperclass)
- myClassReloadingFactory.newInstance("com.jenkov.MyObject");
在自己实现的ClassLoader中,当需要加载MyObjectInterface或者MyObjectSuperclass的时候,要代理给父 ClassLoader去加载。
Java_动态重新加载Class机制的更多相关文章
- Java_动态重新加载Class总结
在此记载Java动态重新加载Class的点点滴滴,实现之前也在网上看了很多文章,但发现不是很清晰,后来发现总结,看源码实现还是最靠谱. 直接上代码: package com.lkb.autoCode. ...
- Android系统下的动态Dex加载
1 问题在Android系统中,一个App的所有代码都在一个Dex文件里面.Dex是一个类似Jar的存储了多有Java编译字节码的归档文件.因为Android系统使用Dalvik虚拟机,所以需要把使用 ...
- Android系统下的动态Dex加载与app速度优化
1 问题 在Android系统中,一个App的所有代码都在一个Dex文件里面.Dex是一个类似Jar的存储了多有Java编译字节码的归档文件.因为Android系统使用Dalvik虚拟机,所以需要把 ...
- 使用javassist运行时动态重新加载java类及其他替换选择
在不少的情况下,我们需要对生产中的系统进行问题排查,但是又不能重启应用,java应用不同于数据库的存储过程,至少到目前为止,还不能原生的支持随时进行编译替换,从这种角度来说,数据库比java的动态性要 ...
- linux动态库加载RPATH, RUNPATH
摘自http://gotowqj.iteye.com/blog/1926771 linux动态库加载RPATH, RUNPATH 链接动态库 如何程序在连接时使用了共享库,就必须在运行的时候能够找到共 ...
- esri-leaflet入门教程(5)- 动态要素加载
esri-leaflet入门教程(5)- 动态要素加载 by 李远祥 在上一章节中已经说明了esr-leaflet是如何加载ArcGIS Server提供的各种服务,这些都是服务本身来决定的,API脚 ...
- 【微信小程序】模仿58同城页面制作以及动态数据加载
完成动态数据的加载,如下 使用上班的空余时间慢慢的学习,相信总有一天我会很熟悉的掌握这门技术. 本次学习小总结: 微信小程序使用的代码基本与HTML.CSS.JS等前段有关知识一样. 微信小程序js使 ...
- libdl.so 动态库加载、查找
使用libdl.so库 动态库加载原理 动态库中函数的查找已经封装成 libdl.so,有4个函数: dlopen : 打开一个动态库 dlsym : 在打开的动态库里找一个函数 dlclo ...
- Vue 动态图片加载路径问题和解决方法
最近在做一个树形结构的组件,使用了Vue和element UI中el-tree组件.因为树中每个节点都需要显示一个图标图片,并且需要根据后台传入的数据类型动态地显示,所以图片的路径需要动态地加载.下面 ...
随机推荐
- 全文搜索 Lucene.Net
Lucene简介 首先说明的是--Lucene.Net只是一个全文检索开发包,不是一个成型的搜索引擎, 它的功能就是负责将文本数据按照某种分词算法进行切词,分词后的结果存储在索引库中,从索引库检索数据 ...
- Javascript的setTimeOut()和setInterval()的定时器用法
Javascript用来处理延时和定时任务的setTimeOut和setInterval函数应用非常广泛,它们都用来处理延时和定时任务,比如打开网页一段时间后弹出一个登录框,页面每隔一段时间发送异步请 ...
- R语言爬虫初尝试-基于RVEST包学习
注意:这文章是2月份写的,拉勾网早改版了,代码已经失效了,大家意思意思就好,主要看代码的使用方法吧.. 最近一直在用且有维护的另一个爬虫是KINDLE 特价书爬虫,blog地址见此: http://w ...
- R语言-用R眼看琅琊榜小说的正确姿势
博客总目录:http://www.cnblogs.com/weibaar/p/4507801.html 目录: 零:写在前面的一些废话 一.R眼看琅琊榜的基本原理 1.导入数据 2.筛选数据 3.多条 ...
- 关于BigDecimal 和 double 类型保存金钱,以及精度问题,银行家舍入法
1. BigDecimal 类型数据 的创建,构造函数 有 public BigDecimal(BigInteger intVal, long val, int scale, int prec); p ...
- PHP如何判断一个数组是一维数组或者是二维数组?用什么函数?
如题:如何判断一个数组是一维数组或者是二维数组?用什么函数? 判断数量即可 <?php if (count($array) == count($array, 1)) { echo '是一维数组' ...
- mysql存储过程学习
一.存储过程的创建 语法: CREATE PROCEDURE sp_name (参数)合法的SQL语句 mysql> delimiter // mysql> CREATE PROCEDUR ...
- nginx配置文件或目录404和403
对于Nginx web目录下的文件,如果不想用户访问那么可以配置返回404或者403状态,默认情况下对于目录来说,如果目录下没有默认文档,那么默认返回是403,也就是不允许查看目录列表,但是如果知道静 ...
- ASM:《X86汇编语言-从实模式到保护模式》第15章:任务切换
15章其实应该是和14章相辅相成的(感觉应该是作者觉得14章内容太多了然后切出来了一点).任务切换和14章的某些概念是分不开的. ★PART1:任务门与任务切换的方法 1. 任务管理程序 14章的时候 ...
- MAC 远程桌面链接 证书或链接无效
RDC --> 首选项 --> 安全性 --> 勾选即使验证失败也要链接. 问题解决.