网络类加载器

背景

因为在深刻jvm虚拟机中看到了有部分说道class能够经过网络的方式加载,因而就想到了是否是能够经过在网络上发布jar包,而后程序动态加载网络上的jar包(可拓展为热更新)java

代码地址

调用模块 https://coding.net/u/mich/p/easytry/git/tree/master/src/com/netclassloadergit

实现模块 https://coding.net/u/mich/p/easytry/git/tree/master/netlogicImpl数组

接口模块 https://coding.net/u/mich/p/easytry/git/tree/master/netlogicInterface网络

说明

该内容主要由三部分组成jvm

  1. 接口模块  主要包含接口jar包
  2. 实现模块     导入接口jar包,而后实现接口的具体逻辑,打包成jar包,最后经过工具包,生成对应的接口文件,将jar包和接口文件都上传至网络,我这里就直接使用了git上的地址,这里还有生成了接口协议文件,相似于双方协议,实现类和调用者的对应关系
  3. 调用模块     自定义一个管理类,下载接口文件与接口jar包,解析jar包中的全部有效class文件,而后将协议文件以及类与class的map存放在成员变量中,当网络加载器加载类指定类时,经过刚才的map获取class文件的byte[],定义该类,管理类同时提供一个获取服务的方法,经过协议文件,将接口与实现类绑定在一块儿

内容

接口模块

接口模块相对来讲比较简单,两个接口ide

package com.netresource.logic;

/**
 * Created by Mich on 2017/7/22.
 */
public interface ISayHello {
    Object sayHello();
}

  

package com.netresource.logic;

/**
 * Created by Mich on 2017/7/22.
 */
public interface ISayWorld {
    Object sayWorld();
}

实现模块

实现模块须要先导入刚才接口模块,而后写两个接口的实现类函数

package com.netlogic;

import com.netresource.logic.ISayHello;

/**
 * Created by Mich on 2017/7/22.
 */
public class SayHelloImpl implements ISayHello {
    @Override
    public Object sayHello() {
        return "Hello";
    }
}
package com.netlogic;

import com.netresource.logic.ISayWorld;

/**
 * Created by Mich on 2017/7/22.
 */
public class SayWorldImpl implements ISayWorld {
    @Override
    public Object sayWorld() {
        return "World";
    }
}

你会发现还有两个util,fileutil主要是我一直使用的对文件的一些处理比较方便,就直接引用了,PropertiesUtil主要是协议文件的生成工具,经过传入实现类的包名,而后扫描该包下的全部类把接口和实现作对应关系存放在output.properties文件中,须要注意的是,若是一个接口并不支持有多个实现类,可是一个实现类实现多个接口是能够的工具

最后将实现类打jar包,以及将协议文件上传至网络,我这里图方便直接放到了coding上https://coding.net/u/mich/p/easytry/git/raw/master/src/com/netclassloader/output/netlogicImpl.jar测试

https://coding.net/u/mich/p/easytry/git/raw/master/src/com/netclassloader/output/output.propertiesthis

调用模块

一样调用模块须要引用接口模块的jar包,而后介绍一下调用模块的具体目录结构(这里无视output文件夹,这主要是我刚才上传的两个文件,jar包和协议文件,为了在一个模块里才放这里,实际不须要这个文件夹)

 

NetClassManager,因为代码有点多就不在这里显示了,具体能够再coding上去看,这里主要介绍一下结构

  1. 构造函数,须要传入两个网络地址,一个是协议文件网络地址,一个是jar包的网络地址
  2. getService经过传入ClassLoader和Class,会根据协议文件的对应关系得到网络jar包上的对应实现类
  3. initProperties初始化协议文件,主要是从网络下载协议文件,而后存放在成员变量中
  4. initImplJar初始化jar包,将jar包暂存在本地,而后解析得到各个内部的class的byte[],经过协议文件,获取所须要的类,存放在classMap成员变量中
  5. getClassMap外部获取对应map,主要是给自定义的classLoader能够得到指定的class的byte[]

NetClassLoader类加载器

package com.netclassloader;

/**
 * Created by Mich on 17/7/17.
 */
public class NetClassLoader extends ClassLoader {
    private NetClassManager netClassManager;

    public NetClassLoader(NetClassManager netClassManager) {
        this.netClassManager = netClassManager;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] bytes = netClassManager.getClassMap().get(name);
        return defineClass(name, bytes, 0, bytes.length);
    }
}

 这个就比较简单了,继承了ClassLoader,构造函数传入刚刚说明的管理类NetClassManager,而后重写了findClass的方法,经过管理类的map来获取字节数组

 

Main做为测试的入口函数

   public static void main(String[] args) {
        String jarUrl = "https://coding.net/u/mich/p/easytry/git/raw/master/src/com/netclassloader/output/netlogicImpl.jar"; String propertiesUrl = "https://coding.net/u/mich/p/easytry/git/raw/master/src/com/netclassloader/output/output.properties"; NetClassManager netClassManager = new NetClassManager(propertiesUrl, jarUrl); NetClassLoader classLoader = new NetClassLoader(netClassManager); ISayHello hello = netClassManager.getService(classLoader, ISayHello.class); ISayWorld world = netClassManager.getService(classLoader, ISayWorld.class); System.out.println(hello.sayHello()); System.out.println(world.sayWorld()); }

 最后就是比较简单的调用了,运行结果

 最后

其实这里也只是抛砖,若是具体使用,应该还须要版本控制,能够有一个专门的类,或者手动调用,去获取最新的jar包,和最新的协议接口文件,固然更好一点能够再添加一个实现类的版本控制,这样就须要修改的粒度更小了。对了若是要添加动态更新还须要修改NetClassLoader类,如今目前只是第一次加载处理,若是有更新,就须要重写loadClass方法了。最后想一想其实协议文件,和版本控制能够直接放在jar包中。。。等下次再继续改进吧。。。

相关文章
相关标签/搜索