likes
comments
collection
share

轻量级IOC框架,基于KOA进行的二次封装

作者站长头像
站长
· 阅读数 13

轻量级IOC框架,基于KOA进行的二次封装

小伙伴们大家好,关于上次期发布的koa-boot框架使用装饰器开发,代码简洁优雅而且逻辑结构清晰。本次更新在此基础上又进行了优化让koa-boot框架使用起来更加得心应手,使其看起来更加的优雅简洁。还没有阅读过上期文章的小伙伴们我会在下面贴出文章链接。希望小伙伴们多多支持,点赞关注收藏一键三连。

关于上期的Koa-Boot框架

更加优雅的koa-boot框架

说了这么多的话,到底优雅在哪里呢? 这里我想说别急,跟着我走,一步一步带你打开 node 优雅开发的大门。

框架目录结构

koa-boot              # 根目录
---src                # 工作目录
----main              # 主目录
-----app              # web服务目录
-----framework        # 框架目录
-----resource         # 资源目录
----test              # 测试目录

优雅的文件引入路径

使用过koa开发的小伙伴都知道引入某个包或者某个目录下面的文件,引入路径都是 ./ 的形式开头后续引入的文件多了代码阅读起来就会相当的费劲如下图

import { 
    AutoWired, 
    Controller, 
    RequestMapping, 
    GetMapping, 
    PostMapping 
}  from '../../framework/src/main/node/context/Decorator'
import SystemService from '../service/SystemService';
import Result from '../../framework/src/main/node/mvc/Result';

...省略部分业务代码

看到处是不是觉得引入的路径阅读起来非常难以理解而且代码看起来非常的不优雅,没有做到见名知意可读性非常的差。因此Koa-boot解决了此痛点代码看起来是这样的

import {
    Autowired,
    Controller,
    GetMapping,
    KoaContext,
    PostMapping,
    RequestMapping,
    RequestParam
} from '@framework/decorator/index'
import KoaBootLogger from "@framework/web/KoaBootLogger";
import KoaBootUtil from "@framework/util/KoaBootUtil";

import SystemService from "@app/service/SystemService";
import User from "@app/entity/User";
import KoaBootRedis from "@framework/web/KoaBootRedis";

...省略部分业务代码

优雅!实在是在太优雅了!对于这个路径别名前端同学很清楚,对于 vscode 会有路径的提示,而且vscode引入的时候也会按照别名引入,让开发者减少引入文件的时间。而且根据路径别名很清晰的知道文件的所在的目录。

async/await 编程开发

使用了一段时间的框架,发现koa大部分插件的实现都是使用异步实现,这对于Koa-Boot来说是毁灭性的打击,因此提供了对异步编程的支持,代码如下

import {Autowired, Controller, PostMapping, RequestMapping} from "@framework/decorator";
import SystemController from "@app/controller/SystemController";

@Controller
@RequestMapping("/user")
class UserController {

    @Autowired
    private systemService: SystemController;

    @PostMapping("/findList")
    public async findList(): Promise<Array<number>> {
        const pageInfo = await systemService.findList();
        return pageInfo;
    }
}
export default UserController;

在controller层的方法上加上了 async 的支持。可以说是支持任何的异步编程,解决了Koa-bootv1.0无法支持异步编程的弊端。

整合Redis

对于Redis后端开发的小伙伴都知道,这是一个非常强大的数据库。数据都是放入内存中因此会经常使用Redis来增加某个接口或者某个功能的性能。Koa-boot对此也进行了整合,使用配置文件的形式来创建Redis实例。实例化后放入IOC容器中,后续使用起来也非常的简单直接进行属性注入即可。

import {
    Autowired, 
    Controller, 
    PostMapping, 
    RequestMapping, 
    GetMapping
} from "@framework/decorator";
import KoaBootRedis from '@framewprd/web/KoaBootRedis'
import SystemController from "@app/controller/SystemController";
import User from "@app/entity/User";


@Controller
@RequestMapping("/user")
class UserController {
    
    @Autowired
    private redisCache: KoaBootRedis;

    @GetMapping("/findOne")
    public async findOne(): Promise<User> {
        const user = awaot redosCacje.getObjectCache('user');
        return user;
    }
}
export default UserController;

整合Mysql

对于后端开发来说数据库是必不可少的一门技术。而MySql是数据库中使用最多的数据库。Koa-boot 对此也进行了整合,通过配置文件就可以直接链接mysql 并且进行开发代码如下

import {Column, PrimaryKey, Table} from "sequelize-typescript";


@Table({
    tableName: "sys_user"
})
class User {

    @Column
    @PrimaryKey
    public id: number;

    @Column
    public userId: number;

    @Column
    public name: string;

    @Column
    public age: number
}

export default User;

众所周知,sequelize 是一门非常优秀的 ORM 框架,Koa-Boot 底层也是使用了 sequelize 进行的封装支持。完全支持 sequelize 的所有api方法。最重要的一点也是使用装饰器进行的开发,这确实非常的优雅。

让框架代码更加优雅的 Reflect 反射技术

初代Koa-Boot中没有引入此技术,使用装饰器封装的代码是这样的

/**
 * 单例池Bean标记
 */
export const componentContainer: Map<string, boolean> = new Map();

/**
 * 属性注入
 */
export const autoWiredContainer: Map<string, Array<Map<string, string>>> = new Map();

/**
 * 组件装饰器
 * @param target 元对象
 */
export function Component(target: any) {
    componentContainer.set(target.name, true);
}

代码上使用了两个Map 对类进行的标记。被标记的类会被创建并且加入到容器中。有非常不好的一点就是这样的实现会让 两个Map 越来越大,后续实例化的时候对于性能非常的不友好。因此引入了反射的概念进行了优化部分实现代码如下

import 'reflect-metadata';

/**
 * 装饰器反射键枚举
 */
export const DECORATOR_SUFFIX = {
    BEAN: "Bean",
    WEB: "Web",
    CONTEXT: "Context",
    QUERY: "Query",
    BODY: "Body",
    PROPERTY: "Property",
    GET: "Get",
    POST: "Post",
    generator: (prefix: string, suffix: string): string => {
        return `${prefix}${suffix}`;
    }
}

/**
 * 组件装饰器
 * @param target
 * @constructor
 */
export function Component(target: any) {
    const beanDefinition = getBeanDefinition(DECORATOR_SUFFIX.generator(target.name,
                                                DECORATOR_SUFFIX.BEAN), target);
    beanDefinition.setTarget(target);
    Reflect.defineMetadata(DECORATOR_SUFFIX.generator(target.name, 
                            DECORATOR_SUFFIX.BEAN), beanDefinition, target);
}

使用反射给类搭上一个标记。在后续扫描到此类时通过 Reflect API获取标记,如果存在标记Koa-Boot则会进行Bean的创建并且自动注入属性。对于性能来说不需要在进行增加额外的遍历和判断就可以直接通过扫描之后进行创建Bean实例,大大的提高了Koa-Boot的性能。

结语

本次优化相当于对整个Koa-Boot进行了重构,初代Koa-Boot或许只是一时的兴起才完成的一个Dome。由于不断加深了TS的理解使用的技术也更加的成熟简洁,对于实现也更加的合理化。有兴趣的小伙伴可以进行源码的阅读。希望小伙伴们多多点赞支持。

源代码传送门