• 使用网络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

  • 相关阅读:
    欧几里得方程 模幂运算 模乘运算 蒙哥马利模乘 素数测试
    HLG 1058workflow解题报告
    poj 3264Balanced Lineup解题报告
    JavaScript之HTMLCollection接口
    随记2(IE下调试Javascript)
    抽象类和接口
    JavaScript之字符串处理函数
    随记1
    多态
    自动内存管理
  • 原文地址:https://www.cnblogs.com/rongfengliang/p/15800247.html
Copyright © 2020-2023  润新知