自定义classload与热加载

场景

  Classload是java语言较为底层的技术,对于自定义框架,中间件开发等都有广泛的应用场景,可以利用它设置出较为灵活的应用。像duckula就是使用它完成插件机制,为扩展duckula提供了可能。还有插件平台,也是使用它来实现ES业务插件的热加载等功能。

双亲委派模型

  类加载这个概念应该算是Java语言的一种创新,目的是为了将类的加载过程与虚拟机解耦,达到”通过类的全限定名来获取描述此类的二进制字节流“的目的。实现这个功能的代码模块就是类加载器。类加载器的基本模型就是大名鼎鼎的双亲委派模型(Parents Delegation Model)。,在需要加载一个类的时候,我们首先判断该类是否已被加载,如果没有就判断是否已被父加载器加载,如果还没有再调用自己的findClass方法尝试加载。基本的模型就是这样:

工具类简化classload

自定义classload

    <dependency>
			<groupId>net.wicp.tams</groupId>
			<artifactId>common-apiext</artifactId>
            <version>最后版本</version>
		</dependency>

示例代码在git库: https://github.com/rjzjh/demo-tams

ext下面有两个目录,demo-tams-apiext-client和demo-tams-apiext-client-new用于模拟热加载。它的代码就是demo-tams-apiext-client模块。

看看如何使用:

private String pluginDir = PathType.getPath("clp:/../../ext");	

private void doClassLoaderPlugin() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
		ClassLoaderPlugin classLoaderPlugin1 = new ClassLoaderPlugin(pluginDir, null, 2);
		Class<?> findClass = classLoaderPlugin1.loadClass("net.wicp.tams.common.apiext.test.services.SayHello");
		Object invokeMothed = ReflectAssist.invokeMothed(findClass.newInstance(), "retHello");
		System.out.println("doClassLoaderPlugin=" + invokeMothed);
		classLoaderPlugin1.close();
		try {
			Class<?> findClass2 = classLoaderPlugin1.loadClass("net.wicp.tams.common.apiext.test.services.SayHello");
			Object invokeMothed2 = ReflectAssist.invokeMothed(findClass2.newInstance(), "retHello");
			System.out.println("doClassLoaderPlugin2=" + invokeMothed2);
		} catch (Exception e) {
			e.printStackTrace();
		}
		ClassLoaderPlugin classLoaderPlugin3 = new ClassLoaderPlugin(pluginDir, null, 2);
		Class<?> findClass3 = classLoaderPlugin3.loadClass("net.wicp.tams.common.apiext.test.services.SayHello");
		Object invokeMothed3 = ReflectAssist.invokeMothed(findClass3.newInstance(), "retHello");
		System.out.println("doClassLoaderPlugin3=" + invokeMothed3);
	}

输出日志:

doClassLoaderPlugin=rjzjh
java.lang.NullPointerException
doClassLoaderPlugin3=rjzjh

关键代码:

ClassLoaderPlugin classLoaderPlugin3 = new ClassLoaderPlugin(pluginDir, null, 2);

pluginDir:自定义classload在哪个目录下去加载类

null: 父classload,null表示当前线程的classload

2: 加载的类在该文件夹的第几层。jar包在目录ext\demo-tams-apiext-client\下,所以是第2层。lib包中的类是通过demo-tams-apiext-client.jar包中的classpath进行加载的。

插件机制

我们实现一个带插件功能一般来说就是主程序里使用接口,主体功能都通过接口完成。而实现类则需要不同插件件来开发,由于某些原因,主程序要保证不能挂,且会做HA机制,那么如何对插件进行热替换也就是插件机制需要考虑的问题。

	private void doPluginHot() throws InstantiationException, IllegalAccessException {
		Plugin plugin = new Plugin(PathType.getPath("clp:/../../ext/demo-tams-apiext-client"),
				"net.wicp.tams.common.apiext.test.services.ISayHello", ClassloadMain.class.getClassLoader(), null,
				Arrays.asList("net.wicp.tams.common.apiext.test.services.ISayHello"), 1);
		Class<?> findClass = plugin.loadSingle();
		Object invokeMothed = ReflectAssist.invokeMothed(findClass.newInstance(), "retHello");
		plugin.close();
		System.out.println("doPlugin=" + invokeMothed);

		Plugin pluginnew = new Plugin(PathType.getPath("clp:/../../ext/demo-tams-apiext-client-new"),
				"net.wicp.tams.common.apiext.test.services.ISayHello", ClassloadMain.class.getClassLoader(), null,
				Arrays.asList("net.wicp.tams.common.apiext.test.services.ISayHello"), 1);
		Class<?> findClassnew = pluginnew.loadSingle();
		Object invokeMothednew = ReflectAssist.invokeMothed(findClassnew.newInstance(), "retHello");
		pluginnew.close();
		System.out.println("doPluginnew=" + invokeMothednew);
	}

上面的代码演示了如何把  demo-tams-apiext-client插件替换为demo-tams-apiext-client-new插件。模拟了插件的热加载。

输出:

doPlugin=rjzjh
doPluginnew=rjzjh+new
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

偏锋书生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值