手撸golangspringioc/aop之2

ioly      2022-02-12     346

关键词:

手撸golang spring ioc/aop 之2

缘起

最近阅读 [Offer来了:Java面试核心知识点精讲(框架篇)] (王磊 , 2020.6)
本系列笔记拟采用golang练习之
Talk is cheap, show me the code.

Spring

Spring基于J2EE技术实现了一套轻量级的
Java Web Service系统应用框架。
它有很多优秀的特性,很多公司都选择把
Spring作为产品或项目的基础开发架构。

Spring的特性包括轻量、控制反转
(Inversion of Control, IoC)、
面向容器、面向切面(AspectOriented 
Programming, AOP)和框架灵活等。

源码gitee地址:
https://gitee.com/ioly/learning.gooop

原文链接:
https://my.oschina.net/ioly

目标

  • 参考spring常用注解,使用golang编写“基于注解的静态代码增强器/生成器”

    • 配置: ComponentScan,Configuration, Bean
    • Bean声明:Component, Service, Controller
    • Bean注入:Autowried
    • AOP注解:Before, After, Around, PointCut

子目标(Day 2)

  • 构思app的运行模式:

    • 本地standlone模式运行
    • 提供基于cli的命令行实时交互
    • 生成旁路代码:只扫描源代码,不修改源代码,增强后的代码加统一后缀
  • 设计cli交互指令集:

    • config save:保存配置
    • config saveas <name>:另存配置
    • watch add <dir>:添加代码扫描目录
    • watch del <dir>:移除代码扫描目录
    • watch list:显示当前扫描的代码目录集合
    • gen:生成增强代码,也就是扫描所有注解,并生成增强类和增强方法

设计

  • config/IConfiguration:配置接口
  • command/ICmd:指令接口
  • command/ICmdBuilder:指令构建器接口
  • command/ICmdContext:指令执行上下文接口
  • config_cmd/SaveCmd: 保存配置
  • config_cmd/SaveASCmd: 另存配置
  • watch_cmd/AddCmd: 添加监视
  • watch_cmd/DelCmd: 移除监视
  • watch_cmd/ListCmd: 显示已监视目录的列表
  • gen_cmd/GenCmd: 生成增强类和增强方法
  • model/IEventDrivenModel:“事件驱动”的逻辑编排模型
  • logger: 日志接口,略

config/IConfiguration.go

配置接口

package config

// IConfiguration defines system configuration interface
type IConfiguration interface {
    GetProjectName() string
    SetProjectName(string)

    GetWatchPaths() []string
    AddWatchPath(string)
    DelWatchPath(string)

    Save() error
    SaveAS(string) error
}

command/ICmd.go

指令接口

package command

import "fmt"

// ICmd defines cli command interface
type ICmd interface {
    fmt.Stringer

    // Apply apply current command into use
    Apply(ICmdContext) error
}

command/ICmdBuilder.go

指令构建器接口

package command

// ICmdBuilder parse input string and create an ICmd instance
type ICmdBuilder interface {
    Build(string) (error, ICmd)
}

command/ICmdContext.go

指令执行上下文接口

package command

import "learning/gooop/spring/autogen/config"

// ICmdContext provides context info for all commands
type ICmdContext interface {
    GetConfiguration() config.IConfiguration
}

config_cmd/SaveCmd.go

保存配置

package config_cmd

import (
    "learning/gooop/spring/autogen/command"
)

// SaveCmd calls service.Save() to save current configuration, in JSON format
type SaveCmd int

// SaveCmdBuilder parse cli input and build a SaveCmd instance
type SaveCmdBuilder int

const gSaveCmdString = "config save"
var gSaveCmdInstance = new(SaveCmd)

func (me *SaveCmd) String() string {
    return gSaveCmdString
}

func (me *SaveCmd) Apply(c command.ICmdContext) error {
    // todo: fixme
    panic("implements me")
}

func (me *SaveCmdBuilder) Build(line string) (error, command.ICmd) {
    if line != gSaveCmdString {
        return nil, nil
    }

    return nil, gSaveCmdInstance
}

config_cmd/SaveASCmd.go

另存配置

package config_cmd

import (
    "errors"
    "learning/gooop/spring/autogen/command"
    "strings"
)

// SaveASCmd calls service.SaveAS() to save current config into specific file, in JSON format
type SaveASCmd struct {
    file string
}

// SaveASCmdBuilder parse cli input and returns a SaveASCmd instance
type SaveASCmdBuilder int

const gSaveASCmdPrefix = "config saveas "

func (me *SaveASCmd) String() string {
    return gSaveASCmdPrefix + me.file
}

func (me *SaveASCmd) Apply(c command.ICmdContext) error {
    // todo: fixme
    panic("implements me")
}

func (me *SaveASCmdBuilder) Build(line string) (error, command.ICmd) {
    if !strings.HasPrefix(line, gSaveASCmdPrefix) {
        return nil, nil
    }

    file := strings.TrimSpace(line[len(gSaveASCmdPrefix):])
    if len(file) <= 0 {
        return errors.New("empty file path"), nil
    }

    return nil, &SaveASCmd{file }
}

watch_cmd/AddCmd.go

添加监视

package watch_cmd

import (
    "learning/gooop/spring/autogen/command"
    "os"
    "strings"
)

// AddCmd calls service.WatchAdd() to add dir to watch list
type AddCmd struct {
    dir string
}

type AddCmdBuilder int

var gAddCmdPrefix = "watch add "

func (me *AddCmd) String() string {
    return gAddCmdPrefix + me.dir
}

func (me *AddCmd) Apply(c command.ICmdContext) error {
    // todo: fixme
    panic("implements me")
}

func (me *AddCmdBuilder) Build(line string) (error, command.ICmd) {
    // check prefix
    if !strings.HasPrefix(line, gAddCmdPrefix) {
        return nil, nil
    }

    // get dir
    dir := strings.TrimSpace(line[len(gAddCmdPrefix):])

    // check dir
    _,e := os.Stat(dir)
    if e != nil {
        return e, nil
    }

    // ok
    return nil, &AddCmd{dir }
}

watch_cmd/DelCmd.go

移除监视

package watch_cmd

import (
    "learning/gooop/spring/autogen/command"
    "os"
    "strings"
)

// DelCmd calls service.WatchDel() to remove dir from watch list
type DelCmd struct {
    dir string
}

type DelCmdBuilder int

var gDelCmdPrefix = "watch del "

func (me *DelCmd) String() string {
    return gDelCmdPrefix + me.dir
}

func (me *DelCmd) Apply(c command.ICmdContext) error {
    // todo: fixme
    panic("implements me")
}

func (me *DelCmdBuilder) Build(line string) (error, command.ICmd) {
    // check prefix
    if !strings.HasPrefix(line, gDelCmdPrefix) {
        return nil, nil
    }

    // get dir
    dir := strings.TrimSpace(line[len(gAddCmdPrefix):])

    // check dir
    _,e := os.Stat(dir)
    if e != nil {
        return e, nil
    }

    // ok
    return nil, &DelCmd{ dir }
}

watch_cmd/ListCmd.go

显示已监视目录的列表

package watch_cmd

import (
    "learning/gooop/spring/autogen/command"
)

// ListCmd calls service.WatchList
type ListCmd int

// ListCmdBuilder parse cli input and try to build a ListCmd instance
type ListCmdBuilder int

const gListCmdString1 = "watch list"
const gListCmdString2 = "watch ls"
var gListCmdSingleton = new(ListCmd)

func (me *ListCmd) String() string {
    return gListCmdString1
}

func (me *ListCmd) Apply(c command.ICmdContext) error {
    // todo:
    panic("implements me")
}

func (me *ListCmdBuilder) Build(line string) (error, command.ICmd) {
    if line != gListCmdString1 && line != gListCmdString2 {
        return nil, nil
    }

    return nil, gListCmdSingleton
}

gen_cmd/GenCmd.go

生成增强类和增强方法

package gen_cmd

import (
    "learning/gooop/spring/autogen/command"
)

// GenCmd calls service.Gen() to generate enhanced code files at once
type GenCmd int

// GenCmdBuilder parse cli input and try to build a GenCmd instance
type GenCmdBuilder int

const gGenCmdString = "gen"
var gGenCmdSingleton = new(GenCmd)

func (me *GenCmd) String() string {
    return gGenCmdString
}

func (me *GenCmd) Apply(c command.ICmdContext) error {
    panic("implements me")
}

func (me *GenCmdBuilder) Build(line string) (error, command.ICmd) {
    if line != gGenCmdString {
        return nil, nil
    }

    return nil, gGenCmdSingleton
}

model/IEventDrivenModel.go

“事件驱动”的逻辑编排模型

package model

// IEventDrivenModel defines an event driven model for code arrangement
type IEventDrivenModel interface {
    Hook(e string, handleFunc TEventHandleFunc)
    Fire(e string, args ...interface{})
    FireAsync(e string, args ...interface{})
}

type TEventHandleFunc func(e string, args ...interface{})

type TEventDrivenModel struct {
    items map[string][]TEventHandleFunc
}

func (me *TEventDrivenModel) Hook(e string, handler TEventHandleFunc) {
    if me.items == nil {
        me.items = make(map[string][]TEventHandleFunc)
    }

    arr, ok := me.items[e]
    if ok {
        me.items[e] = append(arr, handler)
    } else {
        me.items[e] = []TEventHandleFunc{handler}
    }
}

func (me *TEventDrivenModel) Fire(e string, args ...interface{}) {
    if handlers, ok := me.items[e]; ok {
        for _, it := range handlers {
            it(e, args...)
        }
    }
}

func (me *TEventDrivenModel) FireAsync(e string, args ...interface{}) {
    go me.Fire(e, args...)
}

(未完待续)

手撸golangetcdraft协议之11

手撸golangetcdraft协议之11缘起最近阅读[云原生分布式存储基石:etcd深入解析](杜军,2019.1)本系列笔记拟采用golang练习之raft分布式一致性算法分布式存储系统通常会通过维护多个副本来进行容错,以提高系统的可用性。这就引出了... 查看详情

手撸golang仿springioc/aop之4蓝图

手撸golang仿springioc/aop之4蓝图缘起最近阅读[SpringBoot技术内幕:架构设计与实现原理](朱智胜,2020.6)本系列笔记拟采用golang练习之Talkischeap,showmethecode.SpringSpring的主要特性:1.控制反转(InversionofControl,IoC)2.面向容器3.面向切面(Aspect... 查看详情

手撸golang仿springioc/aop之12增强3

手撸golang仿springioc/aop之12增强3缘起最近阅读[SpringBoot技术内幕:架构设计与实现原理](朱智胜,2020.6)本系列笔记拟采用golang练习之Talkischeap,showmethecode.SpringSpring的主要特性:1.控制反转(InversionofControl,IoC)2.面向容器3.面向切面(Aspe... 查看详情

手撸golang仿springioc/aop之5如何扫描

手撸golang仿springioc/aop之5如何扫描缘起最近阅读[SpringBoot技术内幕:架构设计与实现原理](朱智胜,2020.6)本系列笔记拟采用golang练习之Talkischeap,showmethecode.SpringSpring的主要特性:1.控制反转(InversionofControl,IoC)2.面向容器3.面向切面(... 查看详情

手撸golang学etcd手写raft协议之12单元测试

手撸golang学etcd手写raft协议之12单元测试缘起最近阅读[云原生分布式存储基石:etcd深入解析](杜军,2019.1)本系列笔记拟采用golang练习之raft分布式一致性算法分布式存储系统通常会通过维护多个副本来进行容错,以提高系统的可用... 查看详情

手撸golanggo与微服务chatserver之1

缘起最近阅读<<Go微服务实战>>(刘金亮,2021.1)本系列笔记拟采用golang练习之案例需求(聊天服务器)用户可以连接到服务器。用户可以设定自己的用户名。用户可以向服务器发送消息,同时服务器也会向其他用户广播该消息... 查看详情

手撸golanggo与微服务saga模式之1

缘起最近阅读<<Go微服务实战>>(刘金亮,2021.1)本系列笔记拟采用golang练习之Saga模式saga模式将分布式长事务切分为一系列独立短事务每个短事务是可通过补偿动作进行撤销的事务动作和补偿动作都是幂等的,允许重复执行而... 查看详情

手撸golanggo与微服务saga模式之7

缘起最近阅读<<Go微服务实战>>(刘金亮,2021.1)本系列笔记拟采用golang练习之Saga模式saga模式将分布式长事务切分为一系列独立短事务每个短事务是可通过补偿动作进行撤销的事务动作和补动作偿都是幂等的,允许重复执行而... 查看详情

手撸系列之——orm(对象关系映射)(代码片段)

ORM:对象关系映射类》》》数据库的一张表对象》》》表的一条记录对象点属性》》》记录某一个字段对应的值废话不多少,先上代码:#orm.pyfrommysql_singletionimportMysql#设置表字段类,通常需要的属性为字段名,字段类型,是否为... 查看详情

手撸golanggo与微服务chatserver之3压测与诊断

缘起最近阅读<<Go微服务实战>>(刘金亮,2021.1)本系列笔记拟采用golang练习之案例需求(聊天服务器)用户可以连接到服务器。用户可以设定自己的用户名。用户可以向服务器发送消息,同时服务器也会向其他用户广播该消息... 查看详情

goroutine并发调度模型深度解析之手撸一个协程池(代码片段)

golanggoroutine协程池GroutinePool高并发并发(并行),一直以来都是一个编程语言里的核心主题之一,也是被开发者关注最多的话题;Go语言作为一个出道以来就自带『高并发』光环的富二代编程语言,它的并发(并行)编程肯定是... 查看详情

手撸orm

本文目录ORM简介Python中常用ORM框架 原生操作数据库模块pymysqlORM框架之SQLAlchemy手把手带你写一个自己的ORM框架回到目录ORM简介ORM即ObjectRelationalMapping,全称对象关系映射。当我们需要对数据库进行操作时,势必需要通过连接... 查看详情

《spring手撸专栏》第2章:小试牛刀(让新手能懂),实现一个简单的bean容器

作者:小傅哥博客:https://bugstack.cn沉淀、分享、成长,让自己和他人都能有所收获! 查看详情

《spring手撸专栏》第2章:小试牛刀(让新手能懂),实现一个简单的bean容器

作者:小傅哥博客:https://bugstack.cn沉淀、分享、成长,让自己和他人都能有所收获! 查看详情

使用node.js手撸一个建静态web服务器,内部cv指南(代码片段)

...如上图文章结束话说这个键盘真漂亮~~文章目录使用Node.js手撸一个建静态Web服务器一、动静态服务器的概念1.1静态Web服务器概念1.2静态Web服务器的优点1.3快速搭建的途径二、手撸指南2.1框架搭建2.2Ctrl+C/V2.3启动服务器2.4部署服... 查看详情

手撸orm(代码片段)

 ORM即ObjectRelationalMapping,全称对象关系映射。当我们需要对数据库进行操作时,势必需要通过连接数据、调用sql语句、执行sql语句等操作,ORM将数据库中的表,字段,行与我们面向对象编程的类及其方法,属性等一一对应,... 查看详情

10分钟手把手教你用android手撸一个简易的个人记账app(代码片段)

用Android手撸一个简易的个人记账系统⛱️序言📋一、系统结构设计Design1.需求分析2.数据库设计3.界面设计4.过程设计📘二、编码阶段Coding1.项目结构🗂️(1)文件目录(2)AndroidManifest.xml(3)... 查看详情

unity手撸2048小游戏——背景文字控制

今天继续昨天的计划吧1、新建项目、场景命名啥的都不说了吧。2、直接开始新建一个Image,顺便把Image改名成Chessman3、选中Image新建一个Text对象,调整下大小位置。这样就算完成了一格了吧。4、开始撸代码,新建代码命名Chessman... 查看详情