添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

我正在参与 掘金创作者训练营第4期 ,点击了解活动详情,一起学习吧!

近期项目开发已经进入后半段了,目前还有一个积分模块还没实现,具体的积分消费规则没确定下来,导致该功能模块的开发一直搁置着,眼看着时间越来越近了,这么拖着也不是个事,还是得抓紧把他解决掉才行。

基于上述的原因,哗哗哗的就先草草的画了一张流程图出来。

大概的支付流程是这样子的,其中 计费模块 需要通过 折扣模块 积分模块 这两个前置条件处理完之后才进行费用计算。由于 积分规则 暂时只确定了一两种,后续还会新增多种规则,上面领导要求该模块需要实现动态拓展规则功能,不能每次更新都得停机操作。因此该模块的设计上采用了 模板方法模式 来进行实现,通过传入不同的规则名称来获取到对应的实现类进行功能实现。

大概的思路确定了,接下来就是逐渐细化并实现了。

基础规则模块 base

对于规则的实现,这里定义了一个基础模块,该模块里面定义了一个接口,限定了规则需实现的方法,同时也便于后续的逻辑调用,不会因为开发人员各自的命名问题导致需要添加多余的判断。

public interface BaseService {
     * 运行逻辑
     * @param param 参数
     * @return 结果
     * @author unidentifiable
     * @date 2022/2/17 10:50
    String run(String param);

具体功能实现模块 service

功能实现模块,用来实现具体的处理逻辑,在该模块中,我们需要引入上面提到的基础规则模块,实现接口规定的方法。

每一个模块只负责一个规则逻辑的实现,逻辑实现后将其打成Jar包即可。

<dependencies>
    <!-- 引入基础规则 -->
    <dependency>
        <groupId>org.example</groupId>
        <artifactId>base</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>

下面两个类用来模拟不同的扣减规则。

public class MyService1 implements BaseService {
    @Override
    public String run(String param) {
        return "运行扣减规则1:,参数 {" + param + "}";
public class MyService2 implements BaseService {
    @Override
    public String run(String param) {
        return "运行扣减规则2:,参数 {" + param + "}";

Jar包名称保持和类名一致。

使用案例 demo

规则逻辑实现的Jar包已经打好了,接下来就是看我们要怎么来使用它了,这里我们需要实现的功能有两个:

  • 加载Jar
  • 调用实现类的方法
  • 同时这里也需要引用基础规则模块,不然后面加载对应逻辑Jar包的时候会出现异常,找不到对应接口。

    <dependencies>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>base</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
    

    加载Jar包

    加载的方式有好几种,我这里只写了其中一种,有不足之处,还望大家在评论区指出,共同学习功通进步!_{加载的方式有好几种,我这里只写了其中一种,有不足之处,还望大家在评论区指出,共同学习功通进步!}

    * 加载Jar包 * @param jarPath jar包目录 * @author unidentifiable * @date 2022/2/17 15:33 public static void loadJar(String jarPath) throws Exception { // 指定Jar包存放的路径 File files = new File(jarPath); // 找到所有以 .jar 结尾的文件 File[] fileArray = files.listFiles(f -> f.getName().endsWith(".jar")); // 获得类加载器相关方法对象(URLClassLoader:支持从jar包或者文件夹等路径链接中获取class) Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); URLClassLoader classLoader = null; try { // 获取方法的访问权限 method.setAccessible(true); classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); for (File file : fileArray) { // 将当前类路径加到类加载器中 method.invoke(classLoader, file.toURI().toURL()); } finally { method.setAccessible(false); * 运行Jar包内部逻辑 * @param name Jar包名称 * @param param 参数 * @author unidentifiable * @date 2022/2/17 15:33 public static String run(String name, String param) throws Exception { // 类的全路径 String packagePath = "org.example.unidentifiable.service.impl."; Class<?> aClass = null; try { // 得到实现类 aClass = Class.forName(packagePath + name); } catch (ClassNotFoundException e) { return "未找到{" + name + "}规则,请核对后重新提交!"; Object run = null; try { // 调用规则方法 run = aClass.getDeclaredMethod("run", String.class).invoke(aClass.newInstance(), param); } catch (NoSuchMethodException e) { return "规则处理异常,请检查相关资源包:{" + name + "}"; // 返回结果 return run.toString();
    public static void main(String[] args) throws Exception {
        loadJar("F:\");
        System.out.println(run("MyService1", "消费积分"));
        System.out.println("------------------------------------");
        System.out.println(run("MyService2", "赠送积分"));
        System.out.println("------------------------------------");
        System.out.println(run("MyService3", "未知"));
    

    测试了一下,Jar包里面的方法可以正常调用,到这里,一个基础版的动态加载功能已经实现了,先丢上去和领导交差了,又可以愉快的摸鱼去了!

    PS: 网上有一些文章提到了使用完 classLoader 之后需要将其关闭,经过测试,如果关闭了该加载器会导致找不到载入类的异常。 unidentifiable

    私信
    1,014