评论

收藏

[MySQL] 反射reflect实现自定义路由

数据库 数据库 发布于:2021-12-17 18:01 | 阅读数:586 | 评论:0

一、背景
在使用websocket功能的时候要实现根据不同的请求url,执行不同的方法。怎么样能简单一点呢?

解决办法

  • 实际上golnag的 自带路由处理方式。只不过每次都要在里面处理,一个路由定义一个handleFunc方法,如果方法多了确实挺麻烦,每次都要添加
go http.HandleFunc("/", onMessage)
2.实用参数判断基根据每次url的不同来返回对应的结构体然后执行他的对应的方法,这个其实是简单的工厂模式。缺点就是如果该结构提的方法很多的话,调用的参数判断结构就很多哦而且很杂。
DSC0000.png

3.使用反射(reflect)实现,其实现思路是先将所有的结构体存在一个map类型里key则为结构体名字,值则为每个结构体实例。
然后比如请求url参数为 Message/GetUser ,首先分割结构体名字 message从而找到对应的结构体。最后通过MethodByName 找到对应的GetUser方法,然后 执行就可以。本方法实际上有个缺点就是需要还需要手动维护 存结构体的map,但是比之前简单多了一点,具体看代码。
package routers
import (
  "reflect"
  "strings"
  "xfy_whotalk_socket/model"
  "xfy_whotalk_socket/runtime"
  "xfy_whotalk_socket/server"
  "xfy_whotalk_socket/server/message"
  "xfy_whotalk_socket/server/user"
)
var regStruct map[string]interface{}
func init() {
  // 初始化服务map(必须要)
  regStruct = make(map[string]interface{})
  regStruct["User"] = user.NewUserServer()
  regStruct["Message"] = message.NewMessageServer()
}
// @Title GetRouter
// @Description 系统路由
// @Param   method  model.ReceiveMessage   消息类型
// @return code int8
// @return res string
func GetRouter(method model.ReceiveMessage) (code int16, res string) {
  server := server.NewBaseServer()
  methods := strings.Split(method.Method, "/")
  if len(methods) != 2 {
  go server.SendToId(method.Client, method.FromId, 10003, "api参数有误", method.Method, "", 0)
  return
  }
  serverName := methods[0]
  methodName := methods[1]
  if _, ok := regStruct[serverName]; !ok {
  // 不存在
  go server.SendToId(method.Client, method.FromId, 10004, "url not found", method.Method, "", 0)
  return
  }
  code, res = execute(serverName, methodName, method)
  if code > 0 {
  go server.SendToId(method.Client, method.FromId, 10004, res, method.Method, "", 0)
  }
  return
}
// @Title execute
// @Description 通过反射调用对象的操作方法
// @Param   ruleClassName  string   服务名
// @Param   methodName  methodName   方法名
// @Param   message  model.ReceiveMessage   消息结构
// @return code int8
// @return res string
func execute(ruleClassName string, methodName string, message model.ReceiveMessage) (code int16, res string) {
  t := reflect.TypeOf(regStruct[ruleClassName])
  value := reflect.ValueOf(regStruct[ruleClassName])
  if _, ok := t.MethodByName(methodName); !ok {
  return 1, "no method"
  }
  // 所有方法need args 必须要
  args := []reflect.Value{reflect.ValueOf(message)}
  response := value.MethodByName(methodName).Call(args)
  for i := range response {
  if i == 0 {
    x := response[i].Int()
    code = int16(x)
  }
  if i == 1 {
    res = response[i].String()
  }
  }
  runtime.Info.Println("execute--->:", response, code, res)
  return
}
其中有点一需要注意的是,在使用reflect 的 call来执行每个结构体方法的时候,如果有参数必须带上参数 正如上面的例子一样。


// 所有方法need args 必须要
args := []reflect.Value{reflect.ValueOf(message)}
reflect.ValueOf().MethodByName(methodName).Call(args)


反射执行的结果是那个方法的返回结果是一个该方法的执行结果。
DSC0001.png

反射就是动态获取对象的类型,和动态执行他的方法。 比如接口,被赋予各种值以后是没法直接确认他的类型和属性的。






关注下面的标签,发现更多相似文章