go 切面 AOP 实现

go AOP 实现

使用Go语言的反射机制和函数类型实现AOP,通过在需要切入的函数前后添加额外的逻辑代码实现AOP

go 复制代码
package main

import (
	"errors"
	"fmt"
	"log"
	"reflect"
)

// User 结构体表示一个用户
type User struct {
	ID   int
	Name string
}

type Aspect struct {
	Before []func([]reflect.Value) error
	After  []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 nil
	return 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 = 13
	user.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 := 1
	name := "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)
}
相关推荐
青莳吖9 分钟前
Java通过Map实现与SQL中的group by相同的逻辑
java·开发语言·sql
Buleall16 分钟前
期末考学C
java·开发语言
重生之绝世牛码18 分钟前
Java设计模式 —— 【结构型模式】外观模式详解
java·大数据·开发语言·设计模式·设计原则·外观模式
小蜗牛慢慢爬行24 分钟前
有关异步场景的 10 大 Spring Boot 面试问题
java·开发语言·网络·spring boot·后端·spring·面试
Algorithm157634 分钟前
云原生相关的 Go 语言工程师技术路线(含博客网址导航)
开发语言·云原生·golang
shinelord明43 分钟前
【再谈设计模式】享元模式~对象共享的优化妙手
开发语言·数据结构·算法·设计模式·软件工程
Monly211 小时前
Java(若依):修改Tomcat的版本
java·开发语言·tomcat
boligongzhu1 小时前
DALSA工业相机SDK二次开发(图像采集及保存)C#版
开发语言·c#·dalsa
Eric.Lee20211 小时前
moviepy将图片序列制作成视频并加载字幕 - python 实现
开发语言·python·音视频·moviepy·字幕视频合成·图像制作为视频
7yewh1 小时前
嵌入式Linux QT+OpenCV基于人脸识别的考勤系统 项目
linux·开发语言·arm开发·驱动开发·qt·opencv·嵌入式linux