温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

怎么用golang实现基于注解的静态代码增强器/生成器

发布时间:2021-10-13 15:40:30 来源:亿速云 阅读:372 作者:iii 栏目:编程语言

本篇内容主要讲解“怎么用golang实现基于注解的静态代码增强器/生成器”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么用golang实现基于注解的静态代码增强器/生成器”吧!

Spring

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

子目标(Day 6)

  • 昨天把思路撸清楚了,今天动手实现各种词法元素的扫描

    • project.go: 扫描整个项目的所有代码文件。module名从go.mod文件里面取

    • packages.go: 递归扫描某个代码目录

    • files.go: 扫描某个go代码文件,并解析import/struct/field/method等元素

    • imports: 扫描指定代码文件的所有import

    • domain/*.go:词法元素模型集,码略

project.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")

packages.go

递归扫描某个代码目录

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 }

files.go

读入某个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 = "*/"

imports.go

扫描指定代码文件的所有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实现基于注解的静态代码增强器/生成器”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI