缘起
最近阅读 [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常用注解,使用golang编写“基于注解的静态代码增强器/生成器”
- 配置: ComponentScan,Configuration, Bean
- Bean声明:Component, Service, Controller
- Bean注入:Autowried
- AOP注解:Before, After, Around, PointCut
子目标(Day 4)
- 前两天都是在整外围接口,没说清楚到底要搞啥
- 今天以@RestController为例,把项目目标理清楚:
- 以gin框架为基础,描述一个订单CRUD服务
- 以@RestController为例,手写增强前后的代码,描绘如何增强
- 增强前,应当尽可能简洁,降低框架侵入性
- 增强后,与框架很好的结合,把脏活累活默默干好
设计
- OrderController: 订单服务控制器
- OrderController_Enhanced:增强后的订单服务控制器
- 添加SetOrderService方法以便依赖注入
- 添加xxx_Enhanced方法,以集成到gin框架
- 添加RegisterRestController方法,以注册到Bean容器
- 添加init()方法,以便Bean容器引用
- IOrderService:订单持久化服务接口
- MockOrderService:订单持久化服务的实现,码略
- dto/, entity/: 订单服务的实体类和数值类,码略
- IBeanRegistry:bean注册表接口
- IRestController:RESTFul控制器接口
- IControllerRegistry:RESTFul控制器注册表及其默认实现
OrderController.go
订单服务控制器
package controllerimport ("learning/gooop/spring/demo/order/dto""learning/gooop/spring/demo/order/entity""learning/gooop/spring/demo/order/service")// OrderController handles rest requests for CRUD orders// @RestController// @RequestMapping path=/ordertype OrderController struct {orderService service.IOrderService}// Save create or update an order// @PostMappingfunc (me *OrderController) Save(head *entity.OrderHeadEntity, items []*entity.OrderItemEntity) error {return me.orderService.Save(head, items)}// View gets order and order items// @GetMappingfunc (me *OrderController) View(orderID int) (error, *dto.OrderDTO) {return me.orderService.Get(orderID)}// Query query order headers by custom conditions// @GetMappingfunc (me *OrderController) Query(customerID int, statusFlag int, dateFrom string, dateTo string, pageNO int, pageSize int) (error, []*dto.OrderHeadDTO) {return me.orderService.Query(customerID, statusFlag, dateFrom, dateTo, pageNO, pageSize)}
OrderController_Enhanced.go
增强后的订单服务控制器
- 添加SetOrderService方法以便依赖注入
- 添加xxx_Enhanced方法,以集成到gin框架
- 添加RegisterRestController方法,以注册到Bean容器
- 添加init()方法,以便Bean容器引用 ```go package controller
import ( “github.com/gin-gonic/gin” “learning/gooop/spring/demo/framework/bean/controller” “learning/gooop/spring/demo/order/dto” “learning/gooop/spring/demo/order/entity” “learning/gooop/spring/demo/order/service” “net/http” )
// OrderController_Enhanced handles rest requests for CRUD orders // @RestController // @RequestMapping path=/order type OrderController_Enhanced struct { // @Autowired orderService service.IOrderService }
// SetOrderService is auto generated setter method for injecting service.IOrderService into me.orderService func (me *OrderController_Enhanced) SetOrderService(it interface{}) { me.orderService = it.(service.IOrderService) }
// Save create or update an order // @PostMapping func (me OrderController_Enhanced) Save(head entity.OrderHeadEntity, items []*entity.OrderItemEntity) error { return me.orderService.Save(head, items) }
// OrderController_Save_ParamsDTO is auto generated struct for wrapping parameters of OrderController.Save type OrderController_Save_ParamsDTO struct { Order entity.OrderHeadEntity Items []entity.OrderItemEntity }
// View_Enhanced is the enhanced version of Save func (me OrderController_Enhanced) Save_Enhanced(c gin.Context) { r := new(OrderController_Save_ParamsDTO) e := c.BindJSON(r) if e != nil { c.JSON(http.StatusBadRequest, gin.H{“ok”: false, “error”: e.Error()}) return }
e = me.Save(r.Order, r.Items)if e != nil {c.JSON(http.StatusInternalServerError, gin.H{"ok": false, "error": e.Error()})return}c.JSON(http.StatusOK, gin.H{"ok": true})
}
// View gets order and order items // @GetMapping func (me OrderController_Enhanced) View(orderID int) (error, dto.OrderDTO) { return me.orderService.Get(orderID) }
// View_Enhanced is the enhanced version of View func (me OrderController_Enhanced) View_Enhanced(c gin.Context) { id := c.GetInt(“id”) e, d := me.View(id) if e != nil { c.JSON(http.StatusInternalServerError, gin.H{“ok”: false, “error”: e.Error()}) }
c.JSON(http.StatusOK, d)
}
// Query query order headers by custom conditions // @GetMapping func (me OrderController_Enhanced) Query(customerID int, statusFlag int, dateFrom string, dateTo string, pageNO int, pageSize int) (error, []dto.OrderHeadDTO) { panic(“implements me”) }
// OrderController_Query_ParamsDTO is auto generated struct for wrapping parameters of PagedQuery type OrderController_Query_ParamsDTO struct { CustomerID int StatusFlag int DateFrom string DateTO string PageNO int PageSize int }
// Query_Enhanced is the enhanced version of PagedQuery func (me OrderController_Enhanced) Query_Enhanced(c gin.Context) { r := new(OrderController_Query_ParamsDTO) e := c.Bind(r) if e != nil { c.JSON(http.StatusBadRequest, gin.H{“ok”: false, “error”: e.Error()}) return }
e, d := me.Query(r.CustomerID, r.StatusFlag, r.DateFrom, r.DateTO, r.PageNO, r.PageSize)if e != nil {c.JSON(http.StatusInternalServerError, gin.H{"ok": false, "error": e.Error()})return}c.JSON(http.StatusOK, gin.H{"ok": true, "data": d})
}
// RegisterRestController is auto generated to implements controller.IRestController interface func (me OrderController_Enhanced) RegisterRestController(r gin.Engine) { r.POST(“/order/save”, me.Save_Enhanced) r.GET(“/order/view”, me.View_Enhanced) r.GET(“/order/query”, me.Query_Enhanced) }
// init is auto generated to register OrderController_Enhanced into controller.ControllerRegistry func init() { it := new(OrderController_Enhanced) controller.ControllerRegistry.Register(it) }
<a name="XFDpc"></a># IOrderService.go订单持久化服务接口```gopackage serviceimport ("learning/gooop/spring/demo/order/dto""learning/gooop/spring/demo/order/entity")type IOrderService interface {Save(head *entity.OrderHeadEntity, items []*entity.OrderItemEntity) errorGet(orderID int) (error, *dto.OrderDTO)Query(customerID int, statusFlag int, dateFrom string, dateTo string, pageNO int, pageSize int) (error, []*dto.OrderHeadDTO)}
IBeanRegistry.go
bean注册表接口
package beantype IBeanRegistry interface {All() []interface{}}
IRestController.go
RESTFul控制器接口
package controllerimport "github.com/gin-gonic/gin"type IRestController interface {RegisterRestController(r *gin.Engine)}
IControllerRegistry.go
RESTFul控制器注册表及其默认实现
package controllerimport ("github.com/gin-gonic/gin""learning/gooop/spring/demo/framework/bean""sync")type IControllerRegistry interface {bean.IBeanRegistryRegister(it IRestController)Apply(r *gin.Engine)}type tDefaultControllerRegistry struct {rwmutex *sync.RWMutexitems []IRestController}func (me *tDefaultControllerRegistry) All() []interface{} {me.rwmutex.RLock()defer me.rwmutex.RUnlock()all := make([]interface{}, len(me.items))for i, it := range me.items {all[i] = it}return all}func (me *tDefaultControllerRegistry) Register(it IRestController) {me.rwmutex.Lock()defer me.rwmutex.Unlock()me.items = append(me.items, it)}func (me *tDefaultControllerRegistry) Apply(r *gin.Engine) {me.rwmutex.RLock()defer me.rwmutex.RLock()for _, it := range me.items {it.RegisterRestController(r)}}func newDefaultControllerRegistry() IControllerRegistry {return &tDefaultControllerRegistry{new(sync.RWMutex),[]IRestController{},}}var ControllerRegistry = newDefaultControllerRegistry()
(未完待续)
