缘起
最近阅读 [Spring Boot技术内幕: 架构设计与实现原理] (朱智胜 , 2020.6)
本系列笔记拟采用golang练习之
Talk is cheap, show me the code.
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编写“基于注解的静态代码增强器/生成器”
子目标(Day 11)
- 编写针对@RestController的增强器
- enhancer/IEnhancer.go: 定义增强器接口
- enhancer/RestControllerEnhancer.go:REST控制器的增强实现
enhancer/IEnhancer.go:
定义增强器接口
package enhancerimport "learning/gooop/spring/autogen/domain"// IEnhancer clones the original file and appends enhanced codetype IEnhancer interface {Matches(file *domain.CodeFileInfo) boolEnhance(file *domain.CodeFileInfo) (error, *domain.CodeFileInfo)}
enhancer/RestControllerEnhancer.go
REST控制器的增强实现
package controllerimport ("errors""fmt""learning/gooop/spring/autogen/domain""path""strings")type RestControllerEnhancer inttype tMappingMethodInfo struct {httpMethod stringhttpPath stringmethod *domain.MethodInfo}func (me *RestControllerEnhancer) Matches(file *domain.CodeFileInfo) bool {for _, it := range file.Structs {if ok, _ := me.hasAnnotation(it.Annotations, "RestController"); ok {return true}}return false}func (me *RestControllerEnhancer) Enhance(file *domain.CodeFileInfo) (error, *domain.CodeFileInfo) {// clone filefile = file.Clone().(*domain.CodeFileInfo)file.LocalFile = strings.Replace(file.LocalFile, ".go", "_Enhanced.go", -1)// find structs with @RestControllerchanged := falsefor _, it := range file.Structs {if ok, a := me.hasAnnotation(it.Annotations, "RestController"); ok {// enhance target structe := me.enhanceStruct(it, a)if e != nil {return e, nil}changed = true}}if changed {return nil, file} else {return nil, nil}}func (me *RestControllerEnhancer) hasAnnotation(arr []*domain.AnnotationInfo, name string) (bool, *domain.AnnotationInfo) {for _, it := range arr {if it.Name == name {return true, it}}return false, nil}func (me *RestControllerEnhancer) enhanceStruct(s *domain.StructInfo, sa *domain.AnnotationInfo) error {// update struct names.Name = s.Name + "_Enhanced"// ensure importsme.ensureImport(s.CodeFile, "github.com/gin-gonic/gin")me.ensureImport(s.CodeFile, "net/http")// enhance GetMapping methodsmethods := []*tMappingMethodInfo{}for _, it := range s.Methods {if ok, a := me.hasAnnotation(it.Annotations, "GetMapping"); ok {e := me.enhanceGetMapping(it, a)if e != nil {return e}info := new(tMappingMethodInfo)info.httpMethod = "GET"info.httpPath = path.Join(sa.Get("path"), a.Get("path"))info.method = itmethods = append(methods, info)}}// enhance PostMapping methodsfor _, it := range s.Methods {if ok, a := me.hasAnnotation(it.Annotations, "PostMapping"); ok {e := me.enhancePostMapping(it, a)if e != nil {return e}info := new(tMappingMethodInfo)info.httpMethod = "POST"info.httpPath = path.Join(sa.Get("path"), a.Get("path"))info.method = itmethods = append(methods, info)}}// generate RegisterRestController()if len(methods) <= 0 {return errors.New("no mapping method found")}file := s.CodeFileaddLine := func(line string) {file.AdditionalLines = append(file.AdditionalLines, line)}addLine(`// RegisterRestController is auto generated to implements controller.IRestController interface`)addLine(fmt.Sprintf(`func (me *%s) RegisterRestController(r *gin.Engine) {`, s.Name))for _, it := range methods {addLine(fmt.Sprintf(` r.%s("%s", me.%s)`, it.httpMethod, it.httpPath, it.method.Name))}addLine(`}`)return nil}func (me *RestControllerEnhancer) ensureImport(file *domain.CodeFileInfo, p string) {for _, it := range file.Imports {if it.Package == p {return}}// add import infoit := new(domain.ImportInfo)it.CodeFile = fileit.Package = pfile.AdditionalImports = append(file.AdditionalImports, it)}func (me *RestControllerEnhancer) enhanceGetMapping(method *domain.MethodInfo, a *domain.AnnotationInfo) error {// todo: fixmepanic("implements me")}func (me *RestControllerEnhancer) enhancePostMapping(method *domain.MethodInfo, a *domain.AnnotationInfo) error {// todo: fixmepanic("implements me")}
(未完待续)
