# Filter实现AOP

  1. 责任链是很常见的用于解决AOP的一种方式。
  2. 类似的也叫做middleware,interceptor... 本质是一样
  3. Go 函数是一等公民,所以可以考虑使用闭包来实现责任链
  4. filter 很常见,比如说鉴权,日志,tracing,以及跨域等都可以用filter来实现
package main

import (
	"fmt"
	"time"
)

type Filter func(c *Context)

type FilterBuilder func(next Filter) Filter

// 确保MetricFilterBuilder是一个FilterBuilder
var _ FilterBuilder = MetricFilterBuilder

func MetricFilterBuilder(next Filter) Filter {
	return func (c *Context) {
		startTime := time.Now()
		next(c)
		endTime := time.Now()
		fmt.Printf("use time: %f \n", endTime.Sub(startTime).Seconds())
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# Server修改

初始化Server时,允许使用builders并将根节点保存,后续使用

func NewServer(name string, builders... FilterBuilder) Server {
	handler := NewHandlerBaseOnMap()

	var root Filter = func(c *Context) {
		handler.ServeHTTP(c.W, c.R)
	}

	for i:=len(builders)-1; i>=0; i-- {
		b := builders[i]
		root = b(root)
	}

	return &SDKHTTPServer{
		Name: name,
		handler: handler,
		root: root,
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

修改Start函数

func (S *SDKHTTPServer) Start(port string) error {
    // 由 http.Handle() 改为 HandleFunc 则 handle可以不实现ServeHTTP接口
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request){
		S.root(NewContext(w, r))
	})
	return http.ListenAndServe(port, nil)
}
1
2
3
4
5
6
7

# 接口优化

我们看到我们使用Start函数中,在使用root,我们使用NewContext生成了新的Context,但是在NewServer中我又将 Context 拆开了。

func (S *SDKHTTPServer) Start(port string) error {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request){
		S.root(NewContext(w, r)) // 生成了Context
	})
	return http.ListenAndServe(port, nil)
}
1
2
3
4
5
6

NewServer

func NewServer(name string, builders... FilterBuilder) Server {
	...
	var root Filter = func(c *Context) {
		handler.ServeHTTP(c.W, c.R) // 又将Context拆开了,
	}
	...
}
1
2
3
4
5
6
7

# 修改handler

接口修改:

type Handler interface {
	ServeHTTP(ctx *Context) // 直接使用Context
	RouteAble
}
1
2
3
4

实现也修改:

func (h *HandlerBaseOnMap) ServeHTTP(ctx *Context) {
	request := ctx.R
	key := h.key(request.Method, request.URL.Path)
	if handler, ok := h.handlers[key]; ok {
		handler(ctx)
	} else {
		_ = ctx.WriteJSON(http.StatusNotFound, "Not Found")
	}
}
1
2
3
4
5
6
7
8
9

# Server修改

func NewServer(name string, builders... FilterBuilder) Server {
	handler := NewHandlerBaseOnMap()

	var root Filter = handler.ServeHTTP

	for i:=len(builders)-1; i>=0; i-- {
		b := builders[i]
		root = b(root)
	}

	return &SDKHTTPServer{
		Name: name,
		handler: handler,
		root: root,
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 拓展拦截器(中间件)实现

在 Golang 中,拦截器模式(Interceptor Pattern)是一种常见的设计模式,用于在不修改现有代码的情况下增加或修改功能。它通过使用接口(interface)和包装器(wrapper)的方式来实现。

在拦截器模式中,我们通过实现一个接口,然后用一个包装器结构来封装原始对象,从而在调用原始对象的方法之前或之后执行特定的操作。

# 接口实现

// 定义一个接口,包含原始对象的方法
type UserService interface {
    GetUserByID(id int) (User, error)
}

// 原始对象,实现 UserService 接口
type UserServiceImpl struct{}

func (s *UserServiceImpl) GetUserByID(id int) (User, error) {
    // 实际的业务逻辑在这里
    // ...
}

// 包装器结构,用于拦截原始对象的方法调用并执行附加操作
type LoggingInterceptor struct {
    userService UserService
}

func (li *LoggingInterceptor) GetUserByID(id int) (User, error) {
    // 在调用原始方法之前执行的操作
    fmt.Println("Calling GetUserByID with ID:", id)

    // 调用原始方法
    user, err := li.userService.GetUserByID(id)

    // 在调用原始方法之后执行的操作
    if err == nil {
        fmt.Println("GetUserByID succeeded")
    } else {
        fmt.Println("GetUserByID failed with error:", err)
    }

    return user, err
}

// 使用 LoggingInterceptor 封装 UserServiceImpl
func NewLoggingInterceptor(userService UserService) UserService {
    return &LoggingInterceptor{userService: userService}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

# 闭包实现

// 原始对象的函数定义
type GetUserByIDFunc func(id int) (User, error)

// 原始对象的实现
func (fn GetUserByIDFunc) GetUserByID(id int) (User, error) {
    return fn(id)
}

// 包装器函数,用于拦截原始函数调用并执行附加操作
func LoggingInterceptor(getUserByID GetUserByIDFunc) GetUserByIDFunc {
    return func(id int) (User, error) {
        // 在调用原始函数之前执行的操作
        fmt.Println("Calling GetUserByID with ID:", id)

        // 调用原始函数
        user, err := getUserByID(id)

        // 在调用原始函数之后执行的操作
        if err == nil {
            fmt.Println("GetUserByID succeeded")
        } else {
            fmt.Println("GetUserByID failed with error:", err)
        }

        return user, err
    }
}

// 使用 LoggingInterceptor 封装原始函数
userServiceImpl := &UserServiceImpl{}
getUserByIDWithLogging := LoggingInterceptor(userServiceImpl.GetUserByID)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 闭包加接口实现

package __extend_Interceptor

import (
	"fmt"
	"time"
)

type FilterService interface {
	Serve(name string)
}

type MyFilter struct {
}

type FilterServiceBuilder func(next FilterService) FilterService

func (f *MyFilter)Serve(name string) {
	fmt.Printf("MyFilter Serve: %s \n", name)
}

type InterceptorFilter struct {
	next FilterService
}

func (f *InterceptorFilter) Serve(name string) {
	fmt.Printf("InterceptorFilter Serve Start \n")
	f.next.Serve(name)
	fmt.Printf("InterceptorFilter Serve End \n")
}

func NewInterceptorFilter(next FilterService) FilterService {
	return &InterceptorFilter{
		next: next,
	}
}


type MetricFilter struct {
	next FilterService
}

func (f *MetricFilter) Serve(name string) {
	startTime := time.Now()
	f.next.Serve(name)
	endTime := time.Now()
	fmt.Printf("MetricFilter use time: %f \n", endTime.Sub(startTime).Seconds())
}

func NewMetricFilter(next FilterService) FilterService {
	return &MetricFilter{
		next: next,
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

测试调试代码:

package __extend_Interceptor

import "testing"


func TestInterceptor(t *testing.T) {
	r := NewFilterRoot(&MyFilter{}, NewMetricFilter, NewInterceptorFilter)
	r.Serve("hello")
}

//=== RUN   TestInterceptor
//InterceptorFilter Serve Start
//MyFilter Serve: hello
//InterceptorFilter Serve End
//MetricFilter use time: 0.000065
//--- PASS: TestInterceptor (0.00s)
//PASS


type FilterRoot struct {
	root FilterService
}

func (f *FilterRoot)Serve(name string) {
	f.root.Serve(name)
}

func NewFilterRoot(root FilterService, filterServiceBuilders... FilterServiceBuilder) FilterRoot {
	for i:=len(filterServiceBuilders)-1; i>=0; i-- {
		f := filterServiceBuilders[i]
		root = f(root)
	}

	return FilterRoot{
		root: root,
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# 接口加生命周期

package __extend_Interceptor

import "fmt"

// 定义一个接口,包含原始对象的方法以及生命周期函数
type UserService interface {
	// 原始对象的方法
	GetUserByID(id int) string

	// 生命周期函数
	Setup()
	Teardown()
}

// 原始对象,实现 UserService 接口
type UserServiceImpl struct{}

func (s *UserServiceImpl) GetUserByID(id int) string {
	// 实际的业务逻辑在这里
	// ...
	return "李四"
}

func (s *UserServiceImpl) Setup() {
	// 在调用原始方法之前执行的操作
	fmt.Println("UserService setup")
}

func (s *UserServiceImpl) Teardown() {
	// 在调用原始方法之后执行的操作
	fmt.Println("UserService teardown")
}

// 包装器结构,用于拦截原始对象的方法调用并执行附加操作
type LoggingInterceptor struct {
	userService UserService
}

func (li *LoggingInterceptor) GetUserByID(id int) string {
	// 在调用原始方法之前执行的操作
	fmt.Println("Calling GetUserByID with ID:", id)

	// 在调用原始方法之前执行生命周期函数
	li.userService.Setup()

	// 调用原始方法
	name := li.userService.GetUserByID(id)
	fmt.Println(name)

	// 在调用原始方法之后执行生命周期函数
	li.userService.Teardown()

	return name
}

func (li *LoggingInterceptor) Teardown()  {
}

func (li *LoggingInterceptor) Setup()  {
}

// 使用 LoggingInterceptor 封装 UserServiceImpl
func NewLoggingInterceptor(userService UserService) UserService {
	return &LoggingInterceptor{userService: userService}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

测试调试代码

package __extend_Interceptor

import "testing"

func TestLifeHock(t *testing.T) {
	l := NewLoggingInterceptor(&UserServiceImpl{})
	l.GetUserByID(1)
}

//=== RUN   TestLifeHock
//Calling GetUserByID with ID: 1
//UserService setup
//李四
//UserService teardown
//--- PASS: TestLifeHock (0.00s)
//PASS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
上次更新: 10/9/2023,