1.什么是热部署
2.详细讲解classloader
3.实现一个简单的热部署
1.什么是热部署
什么是热部署:在不重启java虚拟机的前提下,自动检测到class文件的变化,并且更新运行时class行为
2.详细讲解classloader
ClassLoader作用:
1.把class加载到JVM中
2.审查每个类由谁负责加载
3.将class字节码重新解析为JVM统一要求的对象格式
ClassLoader分类:
1.启动类加载器
2.扩展类加载器
3.系统类加载器
4.自定义加载器
类的加载过程:
.class 装载到jvm中, 把原料放到工厂中
虚拟机如何加载这些class文件?
装载.class 验证.class是否符合jvm规范 --> 准备:为类的静态变量分配内存,并将其初始化默认值 --> 解析 --> 初始化:为类的静态变量赋予正确的数值
Classloader的加载机制:
启动类加载器:bootstrap classcloader
作用:装载java核心库
扩展类加载器:Ext classloader
作用:装载jdkhome/lib/ext扩展包 同时可以加自定义: :-D java.ext.dirs=指定ext目录
应用程序加载器(系统类加载器):app classloader
作用:负责加载java classpath目录下的类或者jar包
自定义加载器(可以有N个): 继承java.lang.ClassLoader
双亲委派模型: 儿子找父亲,父亲找爷爷
应用程序加载器app classloader ->扩展类加载器Ext classloader ->启动类加载器bootstarp classloader 如果启动类加载器找不到: 启动类加载器 ->扩展类加载器 -> 应用程序加载器 一层一层返回来
自定义java.lang.String 能不能打印?
package java.lang;
public class String {
public static void main(String[] args) {
System.out.println("hello world");
}
}
不能打印,首先加载器会一层一层往上找加载器,当找到启动类加载器时发现java核心类中有该类,所以当运行是运行的是核心类中的String,而核心类中String没有main方法,就报错:
Exception in thread "main" java.lang.NoSuchMethodException: java.lang.String.main([Ljava.lang.String;) 之所以运行不了,它找到顶层中的类加载了
双亲委派模型好处:
1.安全性:保护java核心类不能被覆盖
2.统一性:带着优先级别
对于一个全限定名的java类,只能被加载一次,需要用到自定义类加载器
jvm如何判断两个class是否相同:
1.判断两个类名+全限定名是否形同
2.判断是否有同一个类加载器实施加载的
3.实现一个简单的热部署
/**
* Created by yz on 2018/2/7.
* 自定义类加载器
*/
public class MyClassLoader extends ClassLoader {
/**
* 重写父类方法 Alt+Insert
* @param name : 包名+类名路径
* @return
* @throws ClassNotFoundException
*/
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
//将传进来的java文件转换成class文件
String fileName = name.substring(name.lastIndexOf(".")+1)+".class";
InputStream is = this.getClass().getResourceAsStream(fileName);
try {
byte[] b = new byte[is.available()];
is.read(b);
return defineClass(name,b,0,b.length);
} catch (IOException e) {
e.printStackTrace();
}finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return super.findClass(name);
}
}/**
* Created by yz on 2018/2/7.
*/
public class HelloService {
public void sayHello(){
System.out.println("我是hello world version 2");
}
}
/**
* Created by yz on 2018/2/7.
* 热部署原理测试
*/
public class App {
public static void main(String[] args) throws Exception {
loadHelo();
//动态替换class
System.gc(); //释放当前jvm所占用的class文件,因为装载进去变成正在运行,所以要释放
Thread.sleep(1000);
File old = new File("C:\\Users\\yz\\Desktop\\NioDemo\\hostwap-demo\\target\\classes\\com\\yz\\hostwap\\demo\\HelloService.class");
old.delete();
File newFile = new File("C:\\Users\\yz\\Desktop\\NioDemo\\hostwap-demo\\HelloService.class");
newFile.renameTo(old); //新的文件替换旧的文件
loadHelo(); //重新装载
}
/**
* 使用自定义类加载器
* @throws Exception
*/
public static void loadHelo() throws Exception {
MyClassLoader loader = new MyClassLoader();
Class<?> clazz = loader.findClass("com.yz.hostwap.demo.HelloService");
//通过反射的方式
Object object = clazz.newInstance();
Method method = clazz.getMethod("sayHello");
method.invoke(object);
System.out.println(object.getClass()+" "+object.getClass().getClassLoader());
}
}
热部署原理应用:
Tomcat jsp加载:org.apache.jasper.servlet.JasperLoader