java热加载

来源:互联网 发布:优惠券源码 编辑:程序博客网 时间:2024/05/17 01:14

一晃眼,又是周日了.刚吃完中饭,写篇博客了.

今天就说一说昨天看的java热加载,我们都知道java是从.java文件编译后成为.class文件,再加载到虚拟机中进行运行的....现在的问题是,我们怎么判断一个class文件是否更新了呢?

我们再进行把这个更新后的class文件加载进去呢?


热加载能够节约我们大量的调试时间,避免了因为修改了一个类的一点代码,就全部重启整个项目,像我现在的项目,启动时间就半分钟,旧的等半分钟,也没有别的办法.有了热部署之后就只需要重新加载需改后的java的class文件了.


下面会用代码讲解怎么进行热加载.

1.首先我们先一个借口,实现此接口的类进行热加载

/** * Created by zk on 2017/12/23. * 作用: classload. * 实现这个接口的子类需要动态更新(热加载) */public interface BaseManager {    void logic();}

2.写借口的实现类

/** * Created by zk on 2017/12/23. * 作用: classload. * 实现接口,此类需要实现java类的热加载功能 */public class MyManager implements BaseManager {    @Override    public void logic() {        System.out.println("zhaojun i miss you very much.... ");        System.out.println("today is 周六了");    }}

3.对要进行热加载的类的信息进行封装,方便后面进行类的信息的判断

/** * Created by zk on 2017/12/23. * 作用: classload. * 封装要加载类的信息 */public class LoadInfo {    //自定义的类加载器    private MyClassLoader myClassLoader;    //记录要加载的类的时间戳 --加载的时间    private long loadTime;    private BaseManager baseManager;    public LoadInfo(MyClassLoader myClassLoader, long loadTime) {        this.myClassLoader = myClassLoader;        this.loadTime = loadTime;    }    public void setBaseManager(BaseManager baseManager) {        this.baseManager = baseManager;    }    public MyClassLoader getMyClassLoader() {        return myClassLoader;    }    public long getLoadTime() {        return loadTime;    }    public BaseManager getBaseManager() {        return baseManager;    }}


4.封装自己的classLoad,进行class的重新加载到JVM中去

/** * Created by zk on 2017/12/23. * 作用: classload. * 自定义java类加载器,来实现java的类的热加载 */public class MyClassLoader  extends  ClassLoader{    //要加载的java类的classpath路径    private String classPath;    public MyClassLoader( String classPath) {        super(ClassLoader.getSystemClassLoader());        this.classPath = classPath;    }
    /**
     *  重新父类的方法
    */    @Override    protected Class<?> findClass(String name) throws ClassNotFoundException {        byte[] data=this.loadClassData(name);
        //返回加载后的Class对象
return this.defineClass(name,data,0,data.length); } /** * 加载class文件中的内容 * @param name * @return */ private byte[] loadClassData(String name) { try { name = name.replace(".", "/"); FileInputStream is = new FileInputStream(new File(classPath + name + ".class")); ByteArrayOutputStream bos = new ByteArrayOutputStream(); int b=0; while((b=is.read())!=-1){ bos.write(b); } is.close(); return bos.toByteArray(); } catch (Exception e) { e.printStackTrace(); } return null; }}

5.获取class,对其进行判断,没有加载加重新加载到JVM中去,或者修改了也重新加载

/** * Created by zk on 2017/12/23. * 作用: classload. * 工厂模式,加载manager 的工厂 */public class ManagerFactory {    //加载热加载类的加载信息    private static final Map<String,LoadInfo> loadTimeMap=new HashMap<String,LoadInfo>();    //要加载的类的classpath    public static final String CLASS_PATH="C:/workspace/idea/thinkinJava/out/production/thinkinJava/classload";    //实现热加载的类的全名称,包名+类名    public static final String MY_MANAGER="classload.MyManager";    /**     * 获取manager     * @param className     * @return     */    public static BaseManager getManager(String className){        File loadFile = new File(CLASS_PATH + className.replace(".", "/" + ".class"));        long lastModified=loadFile.lastModified();        //不包含classNamekeyloadinfo信息,证明没有被加载,需要加载这么类到JVM,重新加载,        if(loadTimeMap.get(className)==null){            load(className,lastModified);            //加载类的时间戳变化了,同样重新加载这个类到JVM        }else if(loadTimeMap.get(className).getLoadTime()!=lastModified){            load(className,lastModified);        }        return loadTimeMap.get(className).getBaseManager();    }    public static void load(String className,long lastModified){        MyClassLoader myClassLoader = new MyClassLoader(CLASS_PATH);        Class<?>  loadClass=null;        try {            loadClass=myClassLoader.loadClass(className);        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        BaseManager manager=newInstance(loadClass);        LoadInfo loadInfo = new LoadInfo(myClassLoader, lastModified);        loadInfo.setBaseManager(manager);        loadTimeMap.put(className,loadInfo);    }    /**     * 以反射的方式创建baseManager子类对象     * @param loadClass     * @return     */    private static BaseManager newInstance(Class<?> loadClass) {        try {            return (BaseManager) loadClass.getConstructor(new Class[]{}).newInstance(new Object[]{});        } catch (InstantiationException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        } catch (InvocationTargetException e) {            e.printStackTrace();        } catch (NoSuchMethodException e) {            e.printStackTrace();        }        return null;    }}

6.后台启动一条线程,一直进行监控.与变化就加载进行

/** * Created by zk on 2017/12/23. * 作用: classload. * 后台启动一条线程,刷新重新加载实现了热加载的类 */public class MsgHandle implements  Runnable {    @Override    public void run() {        while (true){            BaseManager manager = ManagerFactory.getManager(ManagerFactory.MY_MANAGER);            manager.logic();            try {                Thread.sleep(1000);            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}

7.编写测试类

/** * Created by zk on 2017/12/23. * 作用: classload. * 测试java类的热加载 * * * 注意IDEA不是实时编译的,请在eclipsedebug试验 */public class ClassLoaderTest {    public static void main(String[] args) {        new Thread(new MsgHandle()).start();    }}


注意使用IDEA需要进行设置.才能看出来效果.下面是设置的链接.注意修改.

http://blog.csdn.net/u013938484/article/details/77541050

使用eclipse直接进行debug,就可以进行热加载了


也不是很复杂.


还有5天就可以回家看昭君了.激动ing.