网络类加载器

背景

由于在深入jvm虚拟机中看到了有部分说道class可以通过网络的方式加载,于是就想到了是不是可以通过在网络上发布jar包,然后程序动态加载网络上的jar包(可拓展为热更新)

代码地址

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

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

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

说明

该内容主要由三部分组成

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

内容

接口模块

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

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.properties

调用模块

同样调用模块需要引用接口模块的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包中。。。等下次再继续改进吧。。。

时间: 2024-11-06 03:30:28

网络类加载器的相关文章

深入探讨 Java 类加载器

转自:http://www.ibm.com/developerworks/cn/java/j-lo-classloader/ 类加载器(class loader)是 Java™中的一个很重要的概念.类加载器负责加载 Java 类的字节代码到 Java 虚拟机中.本文首先详细介绍了 Java 类加载器的基本概念,包括代理模式.加载类的具体过程和线程上下文类加载器等,接着介绍如何开发自己的类加载器,最后介绍了类加载器在 Web 容器和 OSGi™中的应用. 类加载器是 Java 语言的一个创新,也是

深入理解Java类加载器(1):Java类加载原理解析

1 基本信息 每个开发人员对Java.lang.ClassNotFoundExcetpion这个异常肯定都不陌生,这背后就涉及到了java技术体系中的类加载.Java的类加载机制是技术体系中比较核心的部分,虽然和大部分开发人员直接打交道不多,但是对其背后的机理有一定理解有助于排查程序中出现的类加载失败等技术问题,对理解java虚拟机的连接模型和java语言的动态性都有很大帮助. 2 Java虚拟机类加载器结构简述 2.1 JVM三种预定义类型类加载器 我们首先看一下JVM预定义的三种类型类加载器

Java类加载器ClassLoader的说明

(1)API文档内容如下: 类加载器是负责加载类的对象.ClassLoader 类是一个抽象类.如果给定类的二进制名称,那么类加载器会试图查找或生成构成类定义的数据.一般策略是将名称转换为某个文件名,然后从文件系统读取该名称的"类文件". 每个 Class 对象都包含一个对定义它的 ClassLoader 的引用. 数组类的 Class 对象不是由类加载器创建的,而是由 Java 运行时根据需要自动创建.数组类的类加载器由 Class.getClassLoader() 返回,该加载器与

java类加载器-----用户自定义类加载器实现

java类加载器主要分为如下几种: jvm提供的类加载器 根类加载器:底层实现,主要加载java核心类库(如:java.lang.*) 扩展类加载器:使用java代码实现,主要加载如:jre/lib/ext/ 下的扩展类库.(父类加载器为根类加载器) 系统类加载器(应用类加载器):使用java代码实现,加载classpath目录下的类.(父类加载器为扩展类加载器) 用户自定义类加载器:去继承ClassLoader类实现自定义类加载器. 类加载器负责将java字节码文件加载到虚拟机内存中也就是类的

java类加载器(转)

类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一.它使得 Java 类可以被动态加载到 Java 虚拟机中并执行.类加载器从 JDK 1.0 就出现了,最初是为了满足 Java Applet 的需要而开发出来的.Java Applet 需要从远程下载 Java 类文件到浏览器中并执行.现在类加载器在 Web 容器和 OSGi 中得到了广泛的使用.一般来说,Java 应用的开发人员不需要直接同类加载器进行交互.Java 虚拟机默认的行为就已经足够满足大多数情况的需求了.

JVM类加载器原理与自定义类加载器

类加载器原理 JVM将class文件字节码文件加载到内存中, 并将这些静态数据转换成方法区中的运行时数据结构,在堆中生成一个代表这个类的java.lang.Class 对象,作为方法区类数据的访问入口. 类缓存 标准的Java SE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间.不过,JVM垃圾收集器可以回收这些Class过象. 类加载器数状结构 引导类加载器(bootstrap class loader) 它用来加载Java的核心库(JAVA_HOME/

Class.forName(String name)方法,到底会触发那个类加载器进行类加载行为?

4.2 在代码中直接调用Class.forName(String name)方法,到底会触发那个类加载器进行类加载行为? Class.forName(String name)默认会使用调用类的类加载器来进行类加载.我们直接来分析一下对应的jdk的代码: [java] view plain copy //java.lang.Class.java publicstatic Class<?> forName(String className) throws ClassNotFoundExceptio

java之 ------ JUnit、注解、类加载器

JUnit软件测试技术(工具) 在项目中建立专门用户测试的包结构. 在Junit中,通过@Test注解,可以运行一个方法(鼠标放在选择要运行的方法名上,单击右键,选择Run As,再选择JUnit Test即可). 这样做的好处就是不用在主代码中添加测试代码,避免了代码的冗余.而且一个测试类,可以测试多项功能,不需要main方法. 一. Junit注解说明 使用了@Test注解应该满足以下条件: 1) 必须是无参数的非静态方法. 2) 添加@Test注解的类,必须拥有一个无参数的公开构造 pac

Java---注解、类加载器-加强-实现运行任意目录下class中加了@MyTest的空参方法

做自己的类加载器 虚拟机的核心是通过类加载器来加载.class文件,然后进行相应的解析执行.那么我们可以自己做类加载器,手动加载需要的.class以进行解析执行,从而扩展虚拟机的功能. 以下内容摘自API文档: 应用程序需要实现 ClassLoader 的子类,以扩展 Java 虚拟机动态加载类的方式. 网络类加载器子类必须定义方法 findClass 和 loadClassData,以实现从网络加载类.下载组成该类的字节后,它应该使用方法 defineClass 来创建类实例. 代码示例: 自