缘起

最近阅读 [Spring Boot技术内幕: 架构设计与实现原理] (朱智胜 , 2020.6)
本系列笔记拟采用golang练习之
Talk is cheap, show me the code.

Spring

  1. Spring的主要特性:
  2. 1. 控制反转(Inversion of Control, IoC
  3. 2. 面向容器
  4. 3. 面向切面(AspectOriented Programming, AOP
  5. 源码gitee地址:
  6. https://gitee.com/ioly/learning.gooop
  7. 原文链接:
  8. https://my.oschina.net/ioly

目标

  • 参考spring boot常用注解,使用golang编写“基于注解的静态代码增强器/生成器”

子目标(Day 11)

  • 编写针对@RestController的增强器
    • enhancer/IEnhancer.go: 定义增强器接口
    • enhancer/RestControllerEnhancer.go:REST控制器的增强实现

enhancer/IEnhancer.go:
定义增强器接口

  1. package enhancer
  2. import "learning/gooop/spring/autogen/domain"
  3. // IEnhancer clones the original file and appends enhanced code
  4. type IEnhancer interface {
  5. Matches(file *domain.CodeFileInfo) bool
  6. Enhance(file *domain.CodeFileInfo) (error, *domain.CodeFileInfo)
  7. }

enhancer/RestControllerEnhancer.go
REST控制器的增强实现

  1. package controller
  2. import (
  3. "errors"
  4. "fmt"
  5. "learning/gooop/spring/autogen/domain"
  6. "path"
  7. "strings"
  8. )
  9. type RestControllerEnhancer int
  10. type tMappingMethodInfo struct {
  11. httpMethod string
  12. httpPath string
  13. method *domain.MethodInfo
  14. }
  15. func (me *RestControllerEnhancer) Matches(file *domain.CodeFileInfo) bool {
  16. for _, it := range file.Structs {
  17. if ok, _ := me.hasAnnotation(it.Annotations, "RestController"); ok {
  18. return true
  19. }
  20. }
  21. return false
  22. }
  23. func (me *RestControllerEnhancer) Enhance(file *domain.CodeFileInfo) (error, *domain.CodeFileInfo) {
  24. // clone file
  25. file = file.Clone().(*domain.CodeFileInfo)
  26. file.LocalFile = strings.Replace(file.LocalFile, ".go", "_Enhanced.go", -1)
  27. // find structs with @RestController
  28. changed := false
  29. for _, it := range file.Structs {
  30. if ok, a := me.hasAnnotation(it.Annotations, "RestController"); ok {
  31. // enhance target struct
  32. e := me.enhanceStruct(it, a)
  33. if e != nil {
  34. return e, nil
  35. }
  36. changed = true
  37. }
  38. }
  39. if changed {
  40. return nil, file
  41. } else {
  42. return nil, nil
  43. }
  44. }
  45. func (me *RestControllerEnhancer) hasAnnotation(arr []*domain.AnnotationInfo, name string) (bool, *domain.AnnotationInfo) {
  46. for _, it := range arr {
  47. if it.Name == name {
  48. return true, it
  49. }
  50. }
  51. return false, nil
  52. }
  53. func (me *RestControllerEnhancer) enhanceStruct(s *domain.StructInfo, sa *domain.AnnotationInfo) error {
  54. // update struct name
  55. s.Name = s.Name + "_Enhanced"
  56. // ensure imports
  57. me.ensureImport(s.CodeFile, "github.com/gin-gonic/gin")
  58. me.ensureImport(s.CodeFile, "net/http")
  59. // enhance GetMapping methods
  60. methods := []*tMappingMethodInfo{}
  61. for _, it := range s.Methods {
  62. if ok, a := me.hasAnnotation(it.Annotations, "GetMapping"); ok {
  63. e := me.enhanceGetMapping(it, a)
  64. if e != nil {
  65. return e
  66. }
  67. info := new(tMappingMethodInfo)
  68. info.httpMethod = "GET"
  69. info.httpPath = path.Join(sa.Get("path"), a.Get("path"))
  70. info.method = it
  71. methods = append(methods, info)
  72. }
  73. }
  74. // enhance PostMapping methods
  75. for _, it := range s.Methods {
  76. if ok, a := me.hasAnnotation(it.Annotations, "PostMapping"); ok {
  77. e := me.enhancePostMapping(it, a)
  78. if e != nil {
  79. return e
  80. }
  81. info := new(tMappingMethodInfo)
  82. info.httpMethod = "POST"
  83. info.httpPath = path.Join(sa.Get("path"), a.Get("path"))
  84. info.method = it
  85. methods = append(methods, info)
  86. }
  87. }
  88. // generate RegisterRestController()
  89. if len(methods) <= 0 {
  90. return errors.New("no mapping method found")
  91. }
  92. file := s.CodeFile
  93. addLine := func(line string) {
  94. file.AdditionalLines = append(file.AdditionalLines, line)
  95. }
  96. addLine(`// RegisterRestController is auto generated to implements controller.IRestController interface`)
  97. addLine(fmt.Sprintf(`func (me *%s) RegisterRestController(r *gin.Engine) {`, s.Name))
  98. for _, it := range methods {
  99. addLine(fmt.Sprintf(` r.%s("%s", me.%s)`, it.httpMethod, it.httpPath, it.method.Name))
  100. }
  101. addLine(`}`)
  102. return nil
  103. }
  104. func (me *RestControllerEnhancer) ensureImport(file *domain.CodeFileInfo, p string) {
  105. for _, it := range file.Imports {
  106. if it.Package == p {
  107. return
  108. }
  109. }
  110. // add import info
  111. it := new(domain.ImportInfo)
  112. it.CodeFile = file
  113. it.Package = p
  114. file.AdditionalImports = append(file.AdditionalImports, it)
  115. }
  116. func (me *RestControllerEnhancer) enhanceGetMapping(method *domain.MethodInfo, a *domain.AnnotationInfo) error {
  117. // todo: fixme
  118. panic("implements me")
  119. }
  120. func (me *RestControllerEnhancer) enhancePostMapping(method *domain.MethodInfo, a *domain.AnnotationInfo) error {
  121. // todo: fixme
  122. panic("implements me")
  123. }

(未完待续)