关键词:
手撸golang 仿spring ioc/aop 之4 蓝图
缘起
最近阅读 [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 controller
import (
"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=/order
type OrderController struct {
orderService service.IOrderService
}
// Save create or update an order
// @PostMapping
func (me *OrderController) Save(head *entity.OrderHeadEntity, items []*entity.OrderItemEntity) error {
return me.orderService.Save(head, items)
}
// View gets order and order items
// @GetMapping
func (me *OrderController) View(orderID int) (error, *dto.OrderDTO) {
return me.orderService.Get(orderID)
}
// Query query order headers by custom conditions
// @GetMapping
func (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容器引用
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)
}
IOrderService.go
订单持久化服务接口
package service
import (
"learning/gooop/spring/demo/order/dto"
"learning/gooop/spring/demo/order/entity"
)
type IOrderService interface {
Save(head *entity.OrderHeadEntity, items []*entity.OrderItemEntity) error
Get(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 bean
type IBeanRegistry interface {
All() []interface{}
}
IRestController.go
RESTFul控制器接口
package controller
import "github.com/gin-gonic/gin"
type IRestController interface {
RegisterRestController(r *gin.Engine)
}
IControllerRegistry.go
RESTFul控制器注册表及其默认实现
package controller
import (
"github.com/gin-gonic/gin"
"learning/gooop/spring/demo/framework/bean"
"sync"
)
type IControllerRegistry interface {
bean.IBeanRegistry
Register(it IRestController)
Apply(r *gin.Engine)
}
type tDefaultControllerRegistry struct {
rwmutex *sync.RWMutex
items []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()
(未完待续)
手撸golang仿springioc/aop之5如何扫描
手撸golang仿springioc/aop之5如何扫描缘起最近阅读[SpringBoot技术内幕:架构设计与实现原理](朱智胜,2020.6)本系列笔记拟采用golang练习之Talkischeap,showmethecode.SpringSpring的主要特性:1.控制反转(InversionofControl,IoC)2.面向容器3.面向切面(... 查看详情
手撸golang学etcd手写raft协议之12单元测试
手撸golang学etcd手写raft协议之12单元测试缘起最近阅读[云原生分布式存储基石:etcd深入解析](杜军,2019.1)本系列笔记拟采用golang练习之raft分布式一致性算法分布式存储系统通常会通过维护多个副本来进行容错,以提高系统的可用... 查看详情
手撸golangspringioc/aop之2
手撸golangspringioc/aop之2缘起最近阅读[Offer来了:Java面试核心知识点精讲(框架篇)](王磊,2020.6)本系列笔记拟采用golang练习之Talkischeap,showmethecode.SpringSpring基于J2EE技术实现了一套轻量级的JavaWebService系统应用框架。它有很多优秀的... 查看详情
手撸golangetcdraft协议之11
手撸golangetcdraft协议之11缘起最近阅读[云原生分布式存储基石:etcd深入解析](杜军,2019.1)本系列笔记拟采用golang练习之raft分布式一致性算法分布式存储系统通常会通过维护多个副本来进行容错,以提高系统的可用性。这就引出了... 查看详情
手撸golangspringioc/aop之2
参考技术A手撸golangspringioc/aop之2最近阅读[Offer来了:Java面试核心知识点精讲(框架篇)](王磊,2020.6)本系列笔记拟采用golang练习之Talkischeap,showmethecode.配置接口指令接口指令构建器接口指令执行上下文接口保存配置另存配置添加... 查看详情
手撸golanggo与微服务chatserver之1
缘起最近阅读<<Go微服务实战>>(刘金亮,2021.1)本系列笔记拟采用golang练习之案例需求(聊天服务器)用户可以连接到服务器。用户可以设定自己的用户名。用户可以向服务器发送消息,同时服务器也会向其他用户广播该消息... 查看详情
手撸golanggo与微服务saga模式之1
缘起最近阅读<<Go微服务实战>>(刘金亮,2021.1)本系列笔记拟采用golang练习之Saga模式saga模式将分布式长事务切分为一系列独立短事务每个短事务是可通过补偿动作进行撤销的事务动作和补偿动作都是幂等的,允许重复执行而... 查看详情
手撸golanggo与微服务saga模式之7
缘起最近阅读<<Go微服务实战>>(刘金亮,2021.1)本系列笔记拟采用golang练习之Saga模式saga模式将分布式长事务切分为一系列独立短事务每个短事务是可通过补偿动作进行撤销的事务动作和补动作偿都是幂等的,允许重复执行而... 查看详情
手撸golang行为型设计模式模板方法模式
手撸golang行为型设计模式模板方法模式缘起最近复习设计模式拜读谭勇德的<<设计模式就该这样学>>本系列笔记拟采用golang练习之模板方法模式模板方法模式(TemplateMethodPattern)又叫作模板模式,指定义一个操作中的算... 查看详情
手撸golang基本数据结构与算法队列
手撸golang基本数据结构与算法队列缘起最近阅读<<我的第一本算法书>>(【日】石田保辉;宫崎修一)本系列笔记拟采用golang练习之队列队列中的数据也呈线性排列。队列中添加和删除数据的操作分别是在两端进行的。就和... 查看详情
手撸golanggo与微服务chatserver之3压测与诊断
缘起最近阅读<<Go微服务实战>>(刘金亮,2021.1)本系列笔记拟采用golang练习之案例需求(聊天服务器)用户可以连接到服务器。用户可以设定自己的用户名。用户可以向服务器发送消息,同时服务器也会向其他用户广播该消息... 查看详情
手撸golang行为型设计模式访问者模式
手撸golang行为型设计模式访问者模式缘起最近复习设计模式拜读谭勇德的<<设计模式就该这样学>>本系列笔记拟采用golang练习之访问者模式访问者模式(VisitorPattern)是一种将数据结构与数据操作分离的设计模式,指封装... 查看详情
手撸golang基本数据结构与算法冒泡排序
缘起最近阅读<<我的第一本算法书>>(【日】石田保辉;宫崎修一)本系列笔记拟采用golang练习之冒泡排序冒泡排序就是重复“从序列右边开始比较相邻两个数字的大小,再根据结果交换两个数字的位置”这一操作的算法。... 查看详情
手撸golang基本数据结构与算法归并排序
缘起最近阅读<<我的第一本算法书>>(【日】石田保辉;宫崎修一)本系列笔记拟采用golang练习之归并排序归并排序算法会把序列分成长度相同的两个子序列,当无法继续往下分时(也就是每个子序列中只有一个数据时),... 查看详情
goroutine并发调度模型深度解析之手撸一个协程池(代码片段)
golanggoroutine协程池GroutinePool高并发并发(并行),一直以来都是一个编程语言里的核心主题之一,也是被开发者关注最多的话题;Go语言作为一个出道以来就自带『高并发』光环的富二代编程语言,它的并发(并行)编程肯定是... 查看详情
手撸golang基本数据结构与算法网页排名/pagerank,随机游走
缘起最近阅读<<我的第一本算法书>>(【日】石田保辉;宫崎修一)本系列笔记拟采用golang练习之网页排名(PageRank/佩奇排名),随机游走网页排名(PageRank,也叫作佩奇排名)是一种在搜索网页时对搜索结果进行排序的算法。... 查看详情
永恒之蓝漏洞原理及复现
一.介绍。1.什么是永恒之蓝。永恒之蓝(EternalBlue)爆发于2017年4月14日晚,是一种利用Windows系统的SMB协议漏洞来获取系统的最高权限,以此来控制被入侵的计算机。甚至于2017年5月12日,不法分子通过改造“永恒之蓝”制作了wann... 查看详情
手撸系列之——orm(对象关系映射)(代码片段)
ORM:对象关系映射类》》》数据库的一张表对象》》》表的一条记录对象点属性》》》记录某一个字段对应的值废话不多少,先上代码:#orm.pyfrommysql_singletionimportMysql#设置表字段类,通常需要的属性为字段名,字段类型,是否为... 查看详情