go AOP 实现
使用Go语言的反射机制和函数类型实现AOP,通过在需要切入的函数前后添加额外的逻辑代码实现AOP
package mainimport ("errors""fmt""log""reflect"
)// User 结构体表示一个用户
type User struct {ID intName string
}type Aspect struct {Before []func([]reflect.Value) errorAfter []func([]reflect.Value) error
}// Apply 利用反射执行切面的前置和后置处理函数
func (a *Aspect) Apply(targetFunc interface{}, args []reflect.Value) ([]reflect.Value, error) {for _, beforeFunc := range a.Before {if err := beforeFunc(args); err != nil {return nil, err}}result := reflect.ValueOf(targetFunc).Call(args)for _, v := range result {if v.Type().AssignableTo(reflect.TypeOf((*error)(nil)).Elem()) { if v.IsNil() {continue}if err, ok := v.Interface().(error); ok {if err != nil {return nil, err}} else { log.Panicln("Failed to convert return value to error") } }}for _, afterFunc := range a.After {go afterFunc(args)}return result, nil
}func BeforeAspect1(args []reflect.Value) error {id := args[0].Interface().(int)log.Println("BeforeAspect1 get id:", id)return nil
}func BeforeAspect2(args []reflect.Value) error {name := args[1].Interface().(string)log.Println("BeforeAspect2 get name:", name)return nil
}func BeforeAspect3(args []reflect.Value) error {user := args[2].Interface().(*User)log.Println("BeforeAspect3 get user:", user.ID, user.Name)return nilreturn errors.New("BeforeAspect3 error")
}func AfterAspect1(args []reflect.Value) error {log.Println("AfterAspect1")return nil
}func TargetFunction(id int, name string, user *User) (*User, error) {user.ID = 13user.Name = "John Doe"fmt.Printf("Executing target function with ID: %d, Name: %s, User: %+v\n", id, name, user)return user, nil
}func main() {myAspect := &Aspect{Before: []func([]reflect.Value) error{BeforeAspect1, BeforeAspect2,BeforeAspect3,},After: []func([]reflect.Value) error{AfterAspect1,},}// 使用切面执行目标函数targetFuncValue := reflect.ValueOf(TargetFunction)// 构造目标函数的参数值id := 1name := "John"user := &User{ID: 100, Name: "Alice"}args := []reflect.Value{reflect.ValueOf(id),reflect.ValueOf(name),reflect.ValueOf(user),}result, err := myAspect.Apply(targetFuncValue.Interface(), args)if err != nil {fmt.Println("have err:", err)return}fmt.Println("Target function result:", result)
}