手撸golang 仿spring ioc/aop 之3

缘起

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

Spring

Spring基于J2EE技术实现了一套轻量级的Java Web Service零碎利用框架。它有很多优良的个性,很多公司都抉择把Spring作为产品或我的项目的根底开发架构。Spring的次要个性包含:1. 轻量2. 管制反转(Inversion of Control, IoC)3. 面向容器4. 面向切面(AspectOriented Programming, AOP)5. 框架灵便源码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 3)

  • 增加ProjectCmd以反对我的项目定义
  • 增加文本扫描的辅助类:Chars.go, Tokens.go
  • 定义代码生成服务接口ICodingService及其撑持接口

设计

  • command/ProjectCmd: 我的项目定义指令
  • common/Chars: 字符识别辅助类
  • common/Tokens: 组合文本辨认辅助类
  • service/ICodingService: 代码生成服务接口
  • service/iCodingContext: 代码生成上下文
  • service/iCodingState:状态模式下的服务状态
  • service/iCmdRunner:定义指令执行器接口,具体执行拟走责任链模式以便扩大
  • service/tInitialState:默认的服务状态

command/ProjectCmd.go

我的项目定义指令

package project_cmdimport (    "errors"    "fmt"    "learning/gooop/spring/autogen/command"    "learning/gooop/spring/autogen/common"    "os"    "strings")// ProjectCmd defines a project with name and dirtype ProjectCmd struct {    name string    dir string}// ProjectCmdBuilder parses cli input and creates a ProjectCmd instancetype ProjectCmdBuilder intconst gProjectCmdPrefix = "project "var gErrorInvalidProjectCmd = errors.New("invalid project cmd")func (me *ProjectCmd) String() string {    return fmt.Sprintf("project %s %s", me.name, me.dir)}func (me *ProjectCmd) Apply(ctx command.ICmdContext) error {    panic("implements me")}func (me *ProjectCmdBuilder) Build(line string) (error, command.ICmd) {    if !common.Tokens.MatchString(line, gProjectCmdPrefix) {        return nil, nil    }    line = strings.TrimSpace(line[len(gProjectCmdPrefix):])    b,name := common.Tokens.MatchIdentifier(line)    if !b {        return gErrorInvalidProjectCmd, nil    }    line = line[len(name):]    b, spaces := common.Tokens.MatchSpaces(line)    if !b {        return gErrorInvalidProjectCmd, nil    }    line = line[len(spaces):]    b, dir := common.Tokens.MatchDir(line)    if !b {        return gErrorInvalidProjectCmd, nil    }    _,e := os.Stat(dir)    if e != nil {        return e, nil    }    return nil, &ProjectCmd{ name, dir }}

common/Chars.go

字符识别辅助类

package commontype tChars intvar Chars = new(tChars)func (me *tChars) IsSpace(it rune) bool {    switch it {    case ' ':        return true    case '\t':        return true    case '\r':        return true    case '\n':        return true    }    return false}func (me *tChars) Is09(it rune) bool {    return it >= '0' && it <= '9'}func (me *tChars) Is19(it rune) bool {    return it >= '1' && it <= '9'}func (me *tChars) IsLetter(it rune) bool {    return (it >= 'a' && it <= 'z') || (it >= 'A' && it <= 'Z')}func (me *tChars) IsUnderscore(it rune) bool {    return it == '_'}func (me *tChars) IsLB(it rune) bool {    return it == '('}func (me *tChars) IsRB(it rune) bool {    return it == ')'}func (me *tChars) IsChar(it rune, args... rune) bool {    for _,v := range args {        if v == it {            return true        }    }    return false}func (me *tChars) IsSQuote(it rune) bool {    return me.IsChar(it, '\'')}func (me *tChars) IsDQuote(it rune) bool {    return me.IsChar(it, '"')}func (me *tChars) IsRSplash(it rune) bool {    return me.IsChar(it, '\\')}func (me *tChars) IsLSplash(it rune) bool {    return me.IsChar(it, '/')}

common/Tokens.go

组合文本辨认辅助类

package commonimport (    "regexp"    "strings"    "sync")type tTokens struct {    cache map[string]*regexp.Regexp    rwmutex *sync.RWMutex}var Tokens = newTokensLib()func newTokensLib() *tTokens {    it := new(tTokens)    it.init()    return it}func (me *tTokens) init() {    me.cache = make(map[string]*regexp.Regexp)    me.rwmutex = new(sync.RWMutex)}func (me *tTokens) MatchString(s string, p string) bool {    return strings.HasPrefix(s, p)}func (me *tTokens) MatchRegexp(s string, p string) (bool, string) {    me.rwmutex.RLock()    r,ok := me.cache[p]    me.rwmutex.RUnlock()    if !ok {        me.rwmutex.Lock()        if r,ok = me.cache[p];!ok {            r,_ = regexp.Compile(p)        }        me.rwmutex.Unlock()    }    if r == nil {        return false, ""    }    if !r.MatchString(s) {        return false, ""    }    return true, r.FindString(s)}func (me *tTokens) MatchIdentifier(s string) (bool, string) {    return me.MatchRegexp(s, "^[_a-zA-Z]\\w{0,99}}")}func (me *tTokens) MatchSpaces(s string) (bool, string) {    return me.MatchRegexp(s, "^\\s+")}func (me *tTokens) MatchDir(s string) (bool, string) {    b,s := me.MatchRegexp(s, "^([a-zA-Z]\\:)?([\\\\/][^\\s/:*?<>|\\\"\\\\]+)+[\\/]?")    if b {        return b,s    }    b,s = me.MatchRegexp(s, "^\\\"([a-zA-Z]\\:)?([\\\\/][^/:*?<>|\\\"\\\\]+)+[\\/]?\\\"")    if b {        return b,s    }    b,s = me.MatchRegexp(s, "^'([a-zA-Z]\\:)?([\\\\/][^'/:*?<>|\\\"\\\\]+)+[\\/]?'")    if b {        return b,s    }    return false, ""}

service/ICodingService.go

代码生成服务接口

package servicetype ICodingService interface {    iCmdRunner    State() iCodingState    Start()}

service/iCodingContext.go

代码生成上下文

package service// iCodingContext provides context info for iCodingState instancetype iCodingContext interface {    HandleStateChanged(state iCodingState)}

service/iCodingState.go

状态模式下的服务状态

package servicetype iCodingState interface {    iCmdRunner}

service/iCmdRunner.go

定义指令执行器接口,具体执行拟走责任链模式以便扩大

package serviceimport "learning/gooop/spring/autogen/command"// iCmdRunner runs a user cmdtype iCmdRunner interface {    Run(cmd command.ICmd) error}

service/tInitialState.go

默认的服务状态

package serviceimport (    "errors"    "learning/gooop/spring/autogen/command")// tInitialState is the default state for a coding service// it will only accept ProjectCmdtype tInitialState struct {    context iCodingContext}func newInitialState(c iCodingContext) iCodingState {    it := new(tInitialState)    it.init(c)    return it}func (me *tInitialState) init(c iCodingContext) {    me.context = c}var gErrorProjectDefineRequired = errors.New("project not defined: project <name> <dir>")func (me *tInitialState) Run(cmd command.ICmd) error {    panic("implement me")}

(未完待续)