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