j-spring 启动器(5)

81 阅读1分钟

源码:j-spring TS的spring.

前言

启动器的设计为了协调后期各个模块间的异步启动顺序,目前以顺序启动主要为了方便调试,后期可以优化成分批并行启动。

自己先记录下,回头看一遍快速熟悉逻辑,方便优化。

实现

1.接口

springFactory.ts

首先在工厂实例化一个启动器存储集合

//实例化的启动的bean
export const starterBeanList = new Set<SpringStarter>();

export  interface SpringStarter {
    isSpringStater():boolean;
    //启动
    doStart():Promise<any>;
}

function isSpringStarter(bean:any):boolean {
    const starter = bean as SpringStarter;
    return isFunction(starter.doStart) && isFunction(starter.isSpringStater) && starter?.isSpringStater();
}

2.添加实例化的启动器

在工厂装配方法结束后,判断该实例是否满足SpringStarter接口要求。如果是放入启动器集合。

    if(isSpringStarter(bean)){
        starterBeanList.add(bean);
    }

3.运行时顺序执行启动器

export async function invokeStarter():Promise<any>{
    const starterBeanArray = Array.from(starterBeanList);
    for (let index = 0; index < starterBeanArray.length; index++) {
        const element = starterBeanArray[index];
        await element.doStart()
    }
}

export async function launchAsync(clazz:Clazz,args?:any[]):Promise<any> {
    const bootApp = getBootAppBean(clazz);
    await invokeStarter();
    return bootApp.main.apply(bootApp,args||[])
}


export function launch(clazz:Clazz,args?:any[]){
    const bootApp = getBootAppBean(clazz);

    if(starterBeanList.size > 0){
        throw Error(`found starter bean.please use asyncLaunch method!`)
    }

    return bootApp.main.apply(bootApp,args||[])

}

  • 调用launch同步启动函数,如果检测到存在异步启动器则报错
  • 调用launchAsync会先按照装载顺序执行异步启动器

测试用例

模拟持久层和web服务器启动

    
  it('run starter applicaiton by spring and inject more starter ',()=>{
  
    spring.clear();

    @Component
    class Db implements SpringStarter{

      isConnect:string = 'db no';

      isSpringStater(): boolean {
        return true;
      }
      async doStart(): Promise<any> {
        this.isConnect = 'db ok'
      }
    }

    @Component
    class Server implements SpringStarter{

      isStart:string = 'server no';

      isSpringStater(): boolean {
        return true;
      }
      async doStart(): Promise<any> {
        this.isStart = 'server ok'
      }
    }

    @Component
    class Application {

      @Autowired({clazz:Db})
      db:Db;

      @Autowired({clazz:Server})
      server:Server;

      value = 1;
      
      main(){
        return `${this.db.isConnect} ${this.server.isStart}`
      }

    }

    launchAsync(Application).then(v => expect(v).toBe(`db ok server ok`))

  })