使用网络classloader 实现业务功能动态修改加载

日常中我们很多时候是需要进行class的动态加载的而且不希望影响业务,对于java 应用我们
可以开发自己的类加载器可以方便的解决,使用网络类加载器就更加灵活了,可以更好的控制
类的版本以及权限控制,而且灵活性很高(类似rpc,但是运行时还是单体的,rpc 的jvm运行时是跨
主机的)

参考图

 

 

原理说明

还是基于契约的开发模式,包含了一个通用的common-contract 的模块(可以基于抽象以及接口定义)
cust jars 模块主要是基于契约开发的功能模块,开发完成之后基于ci/cd 直接部署到s3中(可以支持多版本
以及访问安全),对于业务入口可以基于网络类加载器加载s3 的jars,然后就可以动态的进行class 的运行加载了

一个参考实例

  • 项目结构

 

 

  • 契约模块
    就是基于接口定义的
 
package com.dalong;
public interface LoginService {
    String printName();
    String printNameVersion(Integer version);
}
  • 契约实现

    注意maven 模块需要引入契约定义

package com.dalong;
 
public class MyApp  implements  LoginService{
    @Override
    public  String printName(){
       return MyUtils.randomUserName();
    }
 
    @Override
    public String printNameVersion(Integer version) {
        return MyUtils.randomUserNameVersion(version);
    }
}
 
 
  • 应用入口
    一个简单spring boot web 项目,服务动态加载部分
 
package com.dalong;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.xeustechnologies.jcl.JarClassLoader;
import org.xeustechnologies.jcl.JclObjectFactory;
import org.xeustechnologies.jcl.ProxyClassLoader;
 
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
 
@Component
 
public class LoginServiceA {
    private JarClassLoader jcl = new JarClassLoader();
    private Logger logger  = LoggerFactory.getLogger(LoginServiceA.class);
    public String printName() throws MalformedURLException {
        logger.info("load class");
        //  每次都加载,当然我们可以自己cache,这样就不用每次都下载了,加载了
        JarClassLoader jcl = new JarClassLoader();
        //Loading classes from different sources
        jcl.add(new URL("http://localhost:8080/userlogin-1-SNAPSHOT.jar"));
        JclObjectFactory factory = JclObjectFactory.getInstance();
        //Create object of loaded class
        logger.info("load class from {}","http://localhost:8080/userlogin-1-SNAPSHOT.jar");
        LoginService obj = (LoginService)factory.create(jcl, "com.dalong.MyApp");
        return obj.printName();
    }
 
    public String printNameVersion(Integer version) throws MalformedURLException {
        //Loading classes from different sources
        JarClassLoader jcl = new JarClassLoader();
        //  每次都加载,当然我们可以自己cache,这样就不用每次都下载了,加载了,此处模拟了多版本的能力
        String requestURL = String.format("http://localhost:8080/userlogin-%d-SNAPSHOT.jar",version);
        jcl.add(new URL(requestURL));
        logger.info("load class from {}",requestURL);
        JclObjectFactory factory = JclObjectFactory.getInstance();
        //Create object of loaded class
        LoginService obj = (LoginService)factory.create(jcl, "com.dalong.MyApp");
        return obj.printNameVersion(version);
    }
}

运行效果

对于契约实现为了简单可以直接暴露到一个静态服务器中就行

 

 

说明

对于开发来说,基于抽象类比接口更加好,因为接口都是需要实现的,抽象类就不一样了,好处是我们可以保证业务代码的二进制兼容,不然每次反而维护很复杂
以上是一个简单的示例,可以扩展下,实现比较强大的业务规则处理

参考资料

https://github.com/sofastack/sofa-ark
https://github.com/kamranzafar/JCL
https://github.com/rongfengliang/jcl-classloader-learning

posted on   荣锋亮  阅读(171)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
历史上的今天:
2021-01-13 pg_stat_monitor pg_stat_statements 的增强扩展
2021-01-13 Replication Between PostgreSQL Versions Using Logical Replication
2020-01-13 几个不错的gc viewer tools
2019-01-13 goreplay 输出流量捕获数据到 elasticsearch
2019-01-13 goreplay 镜像nginx web app流量

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示