热部署:就是在不重启java虚拟机的前提下,自动检测到class文件的变化,并且更新运行时class的行为
jvm判断俩个类是否相同的必要条件:
1、类名必须相同。
2、判断是否由同一个类加载器实施加载的
下面就是利用一个简单的demo来实现类的动态替换:
首先写一个自定义类加载器,用于加载指定的类,代码如下:
package ReBuShu;
import java.io.InputStream;
//定义一个自定义类加载器继承ClassLoader,并且重写findClass方法
public class MyClassLoader extends ClassLoader{
@SuppressWarnings("deprecation")
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String fileName = name.substring(name.lastIndexOf(".")+1)+".class";
InputStream is = this.getClass().getResourceAsStream(fileName);
try {
byte[] h= new byte[is.available()];
is.read(h);
return defineClass(h,0,h.length);
} catch (Exception e) {
// TODO: handle exception
}
return super.findClass(name);
}
}
然后右键选择如下所示,将.java文件编译成.class文件:
然后刷新项目,会看到在target目录下看到编译好的HelloService.class文件,如下所示:
然后将HelloService.class文件拖到项目的根目录下,并且修改HelloService.java文件如下所示:
最后整个项目目录如下所示:
然后编写测试类:
package ReBuShu;
import java.io.File;
import java.lang.reflect.Method;
public class App {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
//加载老的HelloService类的.class文件
loadHello();
System.gc();//释放资源
Thread.sleep(1000);
//获取要替换的老的类的路径
File old = new File("E:\\ideaWorkSpace\\SheJiMoShi\\target\\classes\\ReBuShu\\HelloService.class");
//删除掉老的类
old.delete();
//获取新的类的路径
File newss = new File("HelloService.class");
//替换掉老的class
newss.renameTo(old);
//加载新的HelloService类的.class文件
loadHello();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void loadHello() throws Exception{
MyClassLoader loder = new MyClassLoader();
//通过自定义类加载器加载到HelloService这个类
Class<?> claee = loder.findClass("ReBuShu.HelloService");
//得到对象的实例
Object object = claee.newInstance();
//得到方法;
Method method = claee.getMethod("sayHello");
method.invoke(object);
System.out.println(object.getClass()+" "+object.getClass().getClassLoader());
}
}
运行结果如下所示:
从运行结果可以看出自定义的类加载器先是加载了动态替换之前的类,因为之后加载的类和之前的名相同,所以之后的类就替换了之前加载的类。