运行一个程序,每隔10秒去动态加载一个HelloWorld.java的文件,并执行里面的方法。在这个过程中, 随时可以修改HelloWorld.java文件中的内容,并让修改后的程序及时生效。
其中,HelloWorld.java代码如下:
package com.zhuyun.classloader;
public class HelloWorld{
public void say(String name, int age){
System.out.println("hello, " + name + ", age=" + age);
}
}
使用ClassLoader.getSystemClassLoader().loadClass()或者Class.forName()的方式动态加载类,代码如下:
public static void main(String[] args) throws Exception {
while (true) {
Class> name = Class.forName("com.zhuyun.classloader.HelloWorld");
Object newInstance = name.newInstance();
Method method = name.getDeclaredMethod("say", String.class,int.class);
method.invoke(newInstance, "world", 18);
Thread.sleep(10000);
}
}
执行结果如下:
在执行过程中修改HelloWorld.java的内容,如下:
package com.zhuyun.classloader;
public class HelloWorld{
public void say(String name, int age){
System.out.println("==========hello, " + name + ", age=" + age);
}
}
等10秒后看打印的内容,发现并没有发生变化
说明没有实现我们的需求。
ClassLoader.getSystemClassLoader().loadClass()或者Class.forName()方法使用的类加载器是AppClassLoader,一般也称作系统加载器。它在加载类之前首先会检查类是否已被加载,如果是,它就不会重新加载一次,因此修改的结果不会生效。
因此,使用Java的内置类加载器不可能重新加载类。重新加载一个类你必须实现自己的ClassLoader
子类。
自定义类加载器MyClassLoader.java代码如下:
package com.zhuyun.classloader;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class MyClassLoader extends ClassLoader {
@Override
public Class> findClass(String name) throws ClassNotFoundException {
try {
byte[] classDate = getDate(name);
if (classDate == null) {
}else {
// defineClass方法将字节码转化为类
return defineClass(null, classDate, 0, classDate.length);
}
} catch (IOException e) {
e.printStackTrace();
}
return super.findClass(name);
}
// 返回类的字节码
private byte[] getDate(String className) throws IOException {
InputStream in = null;
ByteArrayOutputStream out = null;
try {
in = new FileInputStream(className);
out = new ByteArrayOutputStream();
byte[] buffer = new byte[2048];
int len = 0;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
return out.toByteArray();
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
in.close();
out.close();
}
return null;
}
}
这个类继承了ClassLoader,我们主要实现findClass的方法,其中defineClass()方法是将字节码转化为类,而提供的HelloWorld.java不是class字节码,因此在加载之前,我们需要先将它编译成字节码。代码如下:
package com.zhuyun.classloader;
import java.lang.reflect.Method;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
public class Main {
public static Class> c;
public static void main(String[] args) throws Exception{
while (true) {
//HelloWorld.java文件的路径
String fileName = "D:/workspace/cassandra_workspace/jvm/HelloWorld.java";
JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager standardFileManager = javaCompiler.getStandardFileManager(null, null, null);
Iterable extends JavaFileObject> iterable = standardFileManager.getJavaFileObjects(fileName);
// 执行编译任务
CompilationTask task = javaCompiler.getTask(null, standardFileManager, null, null, null, iterable);
task.call();
standardFileManager.close();
//自定义类加载器的加载路径
MyClassLoader myClassLoader=new MyClassLoader();
//编译后生成的字节码
c = myClassLoader.findClass("D:/workspace/cassandra_workspace/jvm/HelloWorld.class");
if(c!=null){
Object obj=c.newInstance();
Method method=c.getDeclaredMethod("say", String.class, int.class);
method.invoke(obj, "world", 18);
}
Thread.sleep(10000);
}
}
}
运行结果如下:
在运行过程中修改HelloWorld.java文件
package com.zhuyun.classloader;
public class HelloWorld{
public void say(String name, int age){
System.out.println("==========hello, " + name + ", age=" + age);
}
}
此时,运行结果发生变化
如此一来,就能实现我们的需求了。