自定义 ClassLoader 实现动态加载

不同的classloader加载的相同的类,会被jvm认为是不同的类

要想实现热加载,几个原则是要记住的:

  1. 每次实例化新的classloader
  2. 动态加载类文件,比如rul或者文件等等
  3. 记载的类使用反射进行方法调用,或者上溯为接口进行调用。

下面看一个例子:

首先定义一个被调用的简单类AppObject:

package com.dataguru.jvm.classloader;

public class AppObject {

	public void sayHello(){
		System.out.println("Hello 1.");
	}
}

然后自定义一个ClassLoader的子类HotClassLoader:

package com.dataguru.jvm.classloader;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.Class;
import java.lang.ClassLoader;
import java.lang.ClassNotFoundException;
import java.lang.Override;
import java.lang.String;
import java.lang.System;

public class HotClassLoader extends ClassLoader {

	public HotClassLoader() {
		// TODO Auto-generated constructor stub
	}
	public HotClassLoader(ClassLoader cl) {
		super(cl);
	}

	@Override
	public Class<?> loadClass(String name,boolean resolve) throws ClassNotFoundException {
	 {
		// First, check if the class has already been loaded
		 	Class<?> re = null;
		 	try{
		 		re = findClass(name);
		 	}catch(SecurityException se){
		 		System.out.println(se.getMessage());
		 	}
		    if(re == null){
		        System.out.println("无法载入类:"+name+" 需要请求父加载器");
		        return super.loadClass(name,resolve);
		    }
		    return re;
	    }
	}

	@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException {

		Class<?> cl = null;
		try {
			byte[] data = loadClassBytes(name);
			cl = super.defineClass(name, data, 0, data.length); 
		} catch (IOException e) {
			e.printStackTrace();
		}
		return cl;
	}

	public static byte[] loadClassBytes(String clazzName) throws IOException{
		String resourceName = "/".concat(clazzName.replaceAll("[.]", "/")).concat(".class");
		System.out.println("resource Location:"+resourceName);
		InputStream is = TestMain.class.getResourceAsStream(resourceName);
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		byte[] bt = new byte[1024];
		int l = 0;
		while((l = is.read(bt)) > 0 ){
			baos.write(bt,0,l);
		}
		byte[] rst= baos.toByteArray();
		is.close();
		baos.close();
		return rst;
	}

}

最后写测试类进行测试:

/**
 * 
 */
package com.dataguru.jvm.classloader;

import java.lang.reflect.Method;

/**
 * @author ShenLi
 *
 */
public class TestHotLoad {

	/**
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception {
		HotClassLoader mcl = null;

		while(true){
			mcl = new HotClassLoader();
			Class<?> clz =  mcl.loadClass("com.dataguru.jvm.classloader.AppObject", true);
			mcl = new HotClassLoader();
			Object o = clz.newInstance();
			System.out.println(o);
			Method m = o.getClass().getMethod("sayHello", new Class[] {});
			m.invoke(o, new Object[] {});

			Thread.sleep(5000);
		}
	}

}

注意,每次生成新的classLoader实例,是因为通一个classLoader不能两次加载相同的类,否则会报错。生成的类实例,也不能直接new AppObject()而是要通过反射来调用,或者上溯为接口(还未测试)

测试输出:

resource Location:/com/dataguru/jvm/classloader/AppObject.class
resource Location:/java/lang/Object.class
Prohibited package name: java.lang
无法载入类:java.lang.Object 需要请求父加载器
[email protected]
resource Location:/java/lang/System.class
Prohibited package name: java.lang
无法载入类:java.lang.System 需要请求父加载器
resource Location:/java/io/PrintStream.class
Prohibited package name: java.io
无法载入类:java.io.PrintStream 需要请求父加载器
Hello 1.

将程序改为hello 2后保存编译

这时测试程序并没有退出,而是继续输出,但是输出改变了:

resource Location:/com/dataguru/jvm/classloader/AppObject.class
resource Location:/java/lang/Object.class
Prohibited package name: java.lang
无法载入类:java.lang.Object 需要请求父加载器
[email protected]
resource Location:/java/lang/System.class
Prohibited package name: java.lang
无法载入类:java.lang.System 需要请求父加载器
resource Location:/java/io/PrintStream.class
Prohibited package name: java.io
无法载入类:java.io.PrintStream 需要请求父加载器
Hello 2.

之后反复修改类,均可以实现动态加载。

时间: 2024-10-06 00:41:07

自定义 ClassLoader 实现动态加载的相关文章

dubbo的jmeter压测时jar包的热加载/动态加载

在做dubbo的jmeter压测时,需要把jar包放入jmeter的lib/ext目录下,但是jmeter启动的时候会自动加载这个目录lib目录及lib/ext目录,这样启动后放入这些目录下的jar包就不会加载了. jmeter的master--slave/client模式下,作为jmeter client,jmeter-server服务一直是启动的,当新的jar包放入client后,无法读取,因此需要client的jmeter动态加载这些新放入的jar包. 解决办法参考:http://blog

Java ClassLoader基础及加载不同依赖 Jar 中的公共类

转载自:最新内容及最清晰格式请见 http://www.trinea.cn/android/java-loader-common-class/ 本文主要介绍 ClassLoader 的基础知识,ClassLoader 如何动态加载 Jar,ClassLoader 隔离问题及如何加载不同 Jar 中的公共类. 本文工程开源地址见:Java Dynamic Load [email protected],Clone 以后直接以 Java Application去运行 java-dynamic-load

界面动态加载时报NullPointException

今天在做环境监测的模拟软件时,登陆页面报NullPointException 一般像我们初始化Button时,是Button btn=(Button)findViewById(R.id.button1); 其实完整的写法应该是 Button btn=(Button)this.findViewById(R.id.button1); 但是在onCreate里面,this可以省略. 在自定义的界面动态加载时,需要这样写: EditText et=(EditText)layout.findViewByI

为了实现动态加载而编写的自己的ClassLoader

Copy备用 之前客户要求在不重启应用的前提下实现动态增加服务及交易,在网上查了很长时间也没发现类似的技术,最后研究了一下ClassLoader.因为项目是与Spring,一开始我和同事尝试替换源码的class文件,然后调用Spring的refresh()函数刷新上下文,但是发现原来的类没有被新的类替换.于是我看了一下ClassLoader相关的内容,发现默认的系统类加载器加载类后就不会再次加载.然后我想到要定义自己的类加载器,最后可以实现动态替换原来的类了.虽然最后没能应用在项目中,但是初步了

Qt动态加载ui文件(实现加载客户自定义的一些widget,如QVTKWidget)

利用Qt动态加载ui文件主要是实现ui设计和软件设计的分离,ui只需要向编程人员提供各个控件名称即可.这样做可以满足软件设计后期,由于客户需求,ui风格多变的情况下,不影响编程人员的开发. 具体实现:网上资料较多,一般利用QuiLoader ,只能加载Qwidget 或者QFrame,以下代码主要实现加载的Qwidget 窗口的子窗口有一些用户自定义的Widget ,这里我想加载的是QVTKWidget QString uiFilePath = "E:\\TASK\\CTSoftware\\Qt

Java运行时动态加载类之ClassLoader

https://blog.csdn.net/fjssharpsword/article/details/64922083 *************************************************************************** 需求场景:动态加载类ClassLoaderd,在xml文件中配置加载类名称和方法,: 一.准备 1)在D:\\tmp\\目录下配置a.xml文件: <?xml version="1.0" encoding=&q

动态加载表格数据(自定义)

<!DOCTYPE html><html><head lang="en"> <meta charset="UTF-8"> <title></title> <style> tr>td{ width: 100px; border: 1px solid red; } </style></head><body><ul id="boxU

【转】Android类动态加载技术

http://www.blogjava.net/zh-weir/archive/2011/10/29/362294.html Android应用开发在一般情况下,常规的开发方式和代码架构就能满足我们的普通需求.但是有些特殊问题,常常引发我们进一步的沉思.我们从沉思中产生顿悟,从而产生新的技术形式. 如何开发一个可以自定义控件的Android应用?就像eclipse一样,可以动态加载插件:如何让Android应用执行服务器上的不可预知的代码?如何对Android应用加密,而只在执行时自解密,从而防

Java的动态加载及其安全性问题

1.什么是动态加载 Class Loaders是动态加载Java类与Resource的一种机制.它支持Laziness,type-safe linkage,user-defined extensibility和multiple communicating namespaces这4种特性. Lazy loading:Class只有在需要的时候才加载.这样减少了内存使用量,能提高系统反映速度: Type-safe linkage:动态类加载不会破坏JVM的类型安全: User-definable c