6

手撸golang spring ioc/aop 之2

 3 years ago
source link: https://segmentfault.com/a/1190000039803650
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

手撸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...)
}

(未完待续)


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK