您好,登錄后才能下訂單哦!
本篇內容主要講解“怎么用golang實現基于注解的靜態代碼增強器/生成器”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“怎么用golang實現基于注解的靜態代碼增強器/生成器”吧!
Spring的主要特性: 1. 控制反轉(Inversion of Control, IoC) 2. 面向容器 3. 面向切面(AspectOriented Programming, AOP) 源碼gitee地址: https://gitee.com/ioly/learning.gooop 原文鏈接: https://my.oschina.net/ioly
參考spring boot常用注解,使用golang編寫“基于注解的靜態代碼增強器/生成器”
配置: ComponentScan,Configuration, Bean
Bean聲明:Component, Service, Controller
Bean注入:Autowried
AOP注解:Before, After, Around, PointCut
昨天把思路擼清楚了,今天動手實現各種詞法元素的掃描
project.go: 掃描整個項目的所有代碼文件。module名從go.mod文件里面取
packages.go: 遞歸掃描某個代碼目錄
files.go: 掃描某個go代碼文件,并解析import/struct/field/method等元素
imports: 掃描指定代碼文件的所有import
domain/*.go:詞法元素模型集,碼略
掃描整個項目的所有代碼文件。module名從go.mod文件里面取
package scanner import ( "errors" "io/ioutil" "learning/gooop/spring/autogen/common" "learning/gooop/spring/autogen/domain" "os" "path" "strings" ) func ScanProject(name, dir string) (error, *domain.ProjectInfo) { e, module := parseModFileAndGetModuleName(dir) if e != nil { return e, nil } files, e := ioutil.ReadDir(dir) if e != nil { return e, nil } project := domain.NewProjectInfo() project.Name = name project.LocalDir = dir project.Module = module for _, file := range files { if !file.IsDir() { continue } e, pkg := ScanPackage(project, nil, dir+"/"+file.Name()) if e != nil { return e, nil } else { project.AppendPackage(pkg) } } return nil, project } func parseModFileAndGetModuleName(dir string) (error, string) { modfile := path.Join(dir, gModuleFile) _, e := os.Stat(modfile) if e != nil { return gErrorModuleFileNotFound, "" } data, e := ioutil.ReadFile(modfile) if e != nil { return e, "" } text := string(data) for _, line := range strings.Split(text, "\n") { line := strings.TrimSpace(line) if !common.Tokens.MatchString(line, gModulePrefix) { continue } if ok, s := common.Tokens.MatchRegexp(line, gModulePattern); ok { return nil, strings.TrimSpace(s[len(gModulePrefix)+1:]) } } return gErrorProjectModuleNotFound, "" } var gModuleFile = "go.mod" var gModulePrefix = "module" var gModulePattern = "^module\\s+\\w+(/\\w+)*" var gErrorModuleFileNotFound = errors.New("module file not found: go.mod") var gErrorProjectModuleNotFound = errors.New("project module not found in go.mod")
遞歸掃描某個代碼目錄
package scanner import ( "io/ioutil" "learning/gooop/spring/autogen/domain" "path/filepath" "strings" ) func ScanPackage(project *domain.ProjectInfo, parent *domain.PackageInfo, dir string) (error, *domain.PackageInfo) { pkg := domain.NewPackageInfo() pkg.Project = project pkg.Parent = parent pkg.LocalDir = dir _, f := filepath.Split(dir) pkg.Name = f files, e := ioutil.ReadDir(dir) if e != nil { return e, nil } for _, file := range files { if file.IsDir() { e, p := ScanPackage(project, pkg, dir+"/"+file.Name()) if e != nil { return e, nil } else if p != nil { pkg.AppendPackage(p) } } else if strings.HasSuffix(file.Name(), ".go") { e, f := ScanCodeFile(pkg, dir+"/"+file.Name()) if e != nil { return e, nil } else if f != nil { pkg.AppendFile(f) } } } return nil, pkg }
讀入某個go代碼文件,清除注釋,然后解析import/struct/field/method等元素
package scanner import ( "io/ioutil" "learning/gooop/spring/autogen/common" "learning/gooop/spring/autogen/domain" "regexp" "strings" "unicode" ) func ScanCodeFile(pkg *domain.PackageInfo, file string) (error, *domain.CodeFileInfo) { fbytes, e := ioutil.ReadFile(file) if e != nil { return e, nil } ftext := string(fbytes) lines := strings.Split(ftext, "\n") for i, it := range lines { lines[i] = strings.TrimRightFunc(it, unicode.IsSpace) } codeFile := domain.NewCodeFileInfo() codeFile.Package = pkg codeFile.RawLines = lines // clean comments bInParaComment := false cleanLines := make([]string, len(lines)) for i, it := range lines { s := it if bInParaComment { // para comment end? i := strings.Index(it, gParaCommentEnd) if i >= 0 { bInParaComment = false s = s[i+1:] } else { cleanLines[i] = "" continue } } if common.Tokens.MatchString(it, gLineCommentPrefix) { cleanLines[i] = "" continue } s = removeParaCommentInLine(it) i1 := strings.Index(s, gParaCommentStart) if i1 >= 0 { s = s[:i1] bInParaComment = true } cleanLines[i] = s } // parse imports ScanImport(codeFile) // todo: parse struct declares/fields/methods return nil, nil } func removeParaCommentInLine(s string) string { arr := gParaCommentInLine.FindAllStringIndex(s, -1) if len(arr) > 0 { for i := len(arr) - 1; i >= 0; i-- { from := arr[i][0] to := arr[i][1] s = s[:from] + s[to+1:] } } return s } var gLineCommentPrefix = "^\\s*//" var gParaCommentInLine = regexp.MustCompile("/\\*.*\\*/") var gParaCommentStart = "/*" var gParaCommentEnd = "*/"
掃描指定代碼文件的所有import
package scanner import ( "learning/gooop/spring/autogen/domain" "regexp" ) func ScanImport(file *domain.CodeFileInfo) { parseSingleImport(file) parseMultiImports(file) } func parseSingleImport(file *domain.CodeFileInfo) { for _, it := range file.CleanLines { if gSingleImportRegexp.MatchString(it) { ss := gSingleImportRegexp.FindAllStringSubmatch(it, -1)[0] imp := domain.NewImportInfo() imp.File = file if len(ss) == 3 { imp.Alias = "" imp.Package = ss[1] } else if len(ss) == 5 { imp.Alias = ss[1] imp.Package = ss[3] } file.AppendImport(imp) } } } func parseMultiImports(file *domain.CodeFileInfo) { bInBlock := false for _, it := range file.CleanLines { if bInBlock { if gMultiImportEnd.MatchString(it) { bInBlock = false continue } if gImportPackage.MatchString(it) { ss := gImportPackage.FindAllStringSubmatch(it, -1)[0] imp := domain.NewImportInfo() imp.File = file if len(ss) == 3 { imp.Alias = "" imp.Package = ss[1] } else if len(ss) == 5 { imp.Alias = ss[2] imp.Package = ss[3] } } } if gMultiImportStart.MatchString(it) { bInBlock = true continue } } } var gSingleImportRegexp = regexp.MustCompile(`\s*import\s+((\w+|\.)\s+)?("\w+(/\w+)*")`) var gMultiImportStart = regexp.MustCompile(`^\s*import\s+\(`) var gMultiImportEnd = regexp.MustCompile(`^\s*\)`) var gImportPackage = regexp.MustCompile(`^\s*((\w+|\.)\s+)?("\w+(/\w+)*")`)
到此,相信大家對“怎么用golang實現基于注解的靜態代碼增強器/生成器”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。