乐趣区

关于golang:手撸golang-仿spring-iocaop-之3

手撸 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_cmd

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

// ProjectCmd defines a project with name and dir
type ProjectCmd struct {
    name string
    dir string
}

// ProjectCmdBuilder parses cli input and creates a ProjectCmd instance
type ProjectCmdBuilder int

const 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 common


type tChars int

var 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 common

import (
    "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 service

type ICodingService interface {
    iCmdRunner

    State() iCodingState
    Start()}

service/iCodingContext.go

代码生成上下文

package service

// iCodingContext provides context info for iCodingState instance
type iCodingContext interface {HandleStateChanged(state iCodingState)
}

service/iCodingState.go

状态模式下的服务状态

package service

type iCodingState interface {iCmdRunner}

service/iCmdRunner.go

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

package service

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

// iCmdRunner runs a user cmd
type iCmdRunner interface {Run(cmd command.ICmd) error
}

service/tInitialState.go

默认的服务状态

package service

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

// tInitialState is the default state for a coding service
// it will only accept ProjectCmd
type 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")
}

(未完待续)

退出移动版