Java:ClassLoader实现热加载原理的解析

Posted 你是小KS

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java:ClassLoader实现热加载原理的解析相关的知识,希望对你有一定的参考价值。

1. 声明

当前内容主要为学习和测试实现热加载class的原理:一般class被装载到jvm中的时候此时会触发static的静态代码块执行操作

基本步骤:

  1. 手动创建ClassLoader来加载特定位置上的class文件
  2. 更换new新的ClassLoader来再次测试

2. 基本demo

1.创建需要装载的类

public class NoModifyClass {
	private String name = "NoModifyClass";
	static {
		System.out.println("hello");
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "NoModifyClass [name=" + name + "]";
	}

}

2.开始编写代码进行测试


import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * 
 * @author hy
 * @createTime 2021-07-18 09:39:47
 * @description 当前内容主要为使用热加载器方式加载修改后的class文件
 *
 */
public class HotLoadTest {
	public static void main(String[] args)
			throws InstantiationException, IllegalAccessException, ClassNotFoundException {
		ClassLoader classLoader = HotLoadTest.class.getClassLoader();
		Class<?> loadClass = classLoader.loadClass(NoModifyClass.class.getName());
		Object newInstance = loadClass.newInstance();
		System.out.println(newInstance);
		Class<?> loadClass2 = classLoader.loadClass(NoModifyClass.class.getName());
		Object newInstance2 = loadClass2.newInstance();
		System.out.println(newInstance2);
		MyClassLoader myClassLoader = new MyClassLoader();
		Class<?> loadClass3 = myClassLoader.loadClass(NoModifyClass.class.getName());
		Object newInstance3 = loadClass3.newInstance();
		System.out.println(newInstance3 instanceof NoModifyClass);
		
		// 
		MyClassLoader2 myClassLoader2 = new MyClassLoader2();
		Class<?> loadClass4 = myClassLoader2.loadClass(NoModifyClass.class.getName());
		Object newInstance4 = loadClass4.newInstance();
		System.out.println("newInstance4 instanceof NoModifyClass=" + (newInstance4 instanceof NoModifyClass));


		Class<?> loadClass41 = myClassLoader2.loadClass(NoModifyClass.class.getName());
		Object newInstance41 = loadClass41.newInstance();
		System.out.println("newInstance41 instanceof NoModifyClass=" + (newInstance41 instanceof NoModifyClass));

		// 再次创建一个类加载器,那么加载的类和之前的也不一样
		MyClassLoader2 myClassLoader3 = new MyClassLoader2();
		Class<?> loadClass31 = myClassLoader3.loadClass(NoModifyClass.class.getName());
		Object newInstance31 = loadClass31.newInstance();
		System.out.println("newInstance31 instanceof NoModifyClass=" + (newInstance31 instanceof NoModifyClass));

	}

	static class MyClassLoader extends ClassLoader {

		@Override
		protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
			// TODO Auto-generated method stub
			return super.loadClass(name, resolve);
		}

	}

	static class MyClassLoader2 extends ClassLoader {

		@Override
		public Class<?> loadClass(String name) throws ClassNotFoundException {

			synchronized (getClassLoadingLock(name)) {
				Class<?> loadedClass = findLoadedClass(name);
				// System.out.println("loadedClass=" + loadedClass);

				if (loadedClass == null) {

					String fileName = name.substring(name.lastIndexOf(".") + 1);
					InputStream is = null;
					try {
						fileName = "D:/eclipse-workspace/Java8BasicReStudy/target/classes/com/hy/java/hotload/"
								+ fileName + ".class";

						is = new FileInputStream(new File(fileName));
					} catch (Exception e) {
					}
					if (is == null) {
						// System.out.println("找不到文件:" + fileName);
						return super.loadClass(name);
					}
					try {
						int available = is.available();
						byte[] bytes = new byte[available];
						is.read(bytes);

						return defineClass(bytes, 0, bytes.length);
					} catch (IOException e) {
						throw new ClassNotFoundException();
					}
				}
				return loadedClass;
			}

		}

	}
}

测试结果为:
在这里插入图片描述
只要打印了hello的就表示该类被装载到了jvm中,说明了

  1. 相同的ClassLoader的实例中只能有一份class的定义,如果强制再次加载class文件就会得到Exception in thread "main" java.lang.LinkageError: loader (instance of com/hy/java/hotload/HotLoadTest$MyClassLoader2): attempted duplicate class definition for name: "com/hy/java/hotload/NoModifyClass"这个异常(通过取消findLoadedClass这个可得到异常信息)
  2. 不同的ClassLoader的实例可以加载相同的class定义,这就是热加载class的来源(通过丢弃原来的ClassLoader,new新的ClassLoader就可以了)
  3. 不同的ClassLoader中加载的class最后new出来的实例也是不一样的,无法通过instanceof来判断类型匹配

以上是关于Java:ClassLoader实现热加载原理的解析的主要内容,如果未能解决你的问题,请参考以下文章

java服务器热部署的原理

从Java的类加载机制谈起:聊聊Java中如何实现热部署(热加载)

从Java的类加载机制谈起:聊聊Java中如何实现热部署(热加载)

SpringBoot配置devtools实现热部署

热修复的原理

Eclipse Spring Boot实现热部署