Javascript NodeJS Typescript 动态加载和使用字符串里的类示范,实现热更新热添加热修改策略(核心代码)方案

Javascript NodeJS Typescript 动态加载和使用字符串里的类示范,实现热更新关键策略代码

需求场景

需要动态加载某些模块或者执行某些代码,例如当前我项目核心位置有若干个策略,且需要能热添加、修改、删除,而按照传统做法我需要修改源代码后重新发布项目,不太方便,改一次就要发布一次,重启一次。因此采用如下方案解决
由传统的加载本地模块变为从数据库中查询策略源代码并加载执行
更新代码后,通知所有策略实例热重新启动即可完成更新。

关键技术点验证

动态加载类并创建该类对象

class TestStrategy {
    say() {
        console.log("say function executed!")
    }
}
const TestStrategy = eval('class TestStrategy{say(){console.log("say function executed!")}};TestStrategy')
new TestStrategy().say()

执行结果
在这里插入图片描述

类当中需要依赖其他对象

采用上下文的模式,将所有需要的对象封到上下文Context中,注入解决

策略类

class TestStrategy {
    context;

    setContext(context) {
        this.context = context;
    };

    say() {
        console.log("say function executed!")
    }
}

验证

let context = {
       smile: () => {
           console.log('smile function executed!')
       }
   }
const TestStrategy = eval('class TestStrategy{context;setContext(context){this.context = context;};say(){console.log("say function executed!")}};TestStrategy')
let strategy = new TestStrategy()
strategy.setContext(context)
strategy.context.smile()

执行结果
在这里插入图片描述

导入其他类 import require问题

eval是否支持require验证

Sleep方法

export const Sleep = (ms) => {
    return new Promise(resolve => setTimeout(resolve, ms))
}

测试代码

	const TestStrategy = eval("const utils_1=require('./utils/utils');class TestStrategy{async say(){console.log('say');await utils_1.Sleep(1500);console.log('hi')}};TestStrategy")
    let strategy = new TestStrategy()
    strategy.say()

测试结果:先输出say再1.5秒后输出hi
在这里插入图片描述
实验结果证明eval中能使用require

路径问题

由于我的策略结构如下,之前例如grid.strategy.ts中导入其他模块的相对目录是从strategy/impl开始的,而我现在使用动态加载字符串源码之后,加载代码会到工厂里,目录改变了,因此我们直接图方便把工厂类放到impl文件夹下即可最小化改动解决相对路径问题
工厂的创建策略实例对象方法从之前的传入策略名、上下文变为传入策略源代码字符串、上下文

移动前
在这里插入图片描述
在这里插入图片描述
移动后
在这里插入图片描述

在这里插入图片描述

ts如何变源码字符串呢?

  1. 先在IDE里编辑好你的ts代码,并启动项目,在dist目录中便会有编译后的js代码
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  2. 截取关键部分
    在这里插入图片描述
  3. 压缩成一行并在最后加上分号和类名,比如 ;TestStrategy
    在这里插入图片描述
const utils_1=require("../../utils/utils");class TestStrategy{async say(){console.log("say");await utils_1.Sleep(1500);console.log("hi")}} ;TestStrategy
  1. 即可使用该字符串作为该策略的源码修改到数据库中去,实现热修改、热添加、热更新

热重启

  1. 实时通知重启

对策略实例管理器接口增加reload(strategy: Strategy)接口,在更新代码后对每个策略调用重新加载

  1. 定时检查源码版本号重启

定时检查当前使用的源码版本号和数据库中最新的源码版本号,如果不一致则重启自己。

  • 结语
    最后试验是成功完成了的,顺利从数据库拉取策略源码并使用源码创建实例对数据进行模拟回测
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

posted @ 2021-07-19 10:57  HumorChen99  阅读(17)  评论(0编辑  收藏  举报  来源