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

今天就说一说昨天看的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();
        //不包含className为key的loadinfo信息,证明没有被加载,需要加载这么类到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不是实时编译的,请在eclipse上debug试验
 */
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,就可以进行热加载了

 

Java Framework,欢迎各位前来交流java相关
QQ群:965125360

 

 

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐