仿照java的jdk动态代理实现go语言动态代理

仿照java的jdk动态代理实现go语言动态代理

通过学习java的jdk动态代理和Cglib动态代理,仿照jdk动态代理用go实现了一个简单的动态代理

结构型模式

代理模式

代理模式中分为静态代理和动态代理。静态代理需要在编译前就要写好,而动态代理需要在运行时通过反射来实现方法增强。

静态代理:

  1. 代理类实现和目标类相同的接口,每个类都单独编辑一个代理类。
  2. 我们需要在代理类中,将目标类中的所有方法都要重新实现,并且为每个方法都附加相似的代码逻辑。
  3. 如果要添加方法增强的类不止一个,我们需要对每个类都创建一个代理类。

动态代理:

  1. 不需要为每个目标类编辑代理类。
  2. 在程序运行时,系统会动态地创建代理类,然后用代理类替换掉原始类。
  3. 一般采用反射实现。

代理模式的优点:

  1. 代理模式能将代理对象与真实被调用目标对象分离。
  2. 在一定程度上降低了系统的耦合性,拓展性好。
  3. 可以起到保护目标对象的作用。
  4. 可以增强目标对象的功能。

动态代理实现

package pro

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

//提供动态调用方法接口
type InvocationHandler interface {
   Invoke(proxy *Proxy, method *Method, args []interface{}) ([]interface{}, error)
}

//代理,用来总管代理类的生成
type Proxy struct {
   target  interface{}        //目标类,后面的类型和java的Object一样
   methods map[string]*Method //map用来装载待增强的不同的方法
   handle  InvocationHandler  //用来暴露统一invoke接口,类似多态
}

//创建新的代理
func NewProxy(target interface{}, h InvocationHandler) *Proxy {
   typ := reflect.TypeOf(target)          //用来显示目标类动态的真实类型
   value := reflect.ValueOf(target)       //获取目标类的值
   methods := make(map[string]*Method, 0) //初始化目标类的方法map
   //将目标类的方法逐个装载
   for i := 0; i < value.NumMethod(); i++ {
      method := value.Method(i)
      methods[typ.Method(i).Name] = &Method{value: method}
   }
   return &Proxy{target: target, methods: methods, handle: h}
}

//代理调用代理方法
func (p *Proxy) InvokeMethod(name string, args ...interface{}) ([]interface{}, error) {
   return p.handle.Invoke(p, p.methods[name], args)
}

//用来承载目标类的方法定位和调用
type Method struct {
   value reflect.Value //用来装载方法实例
}

//这里相当于调用原方法,在该方法外可以做方法增强,需要调用者自己实现!!!
func (m *Method) Invoke(args ...interface{}) (res []interface{}, err error) {
   defer func() {
      //用来捕捉异常
      if p := recover(); p != nil {
         err = errors.New(fmt.Sprintf("%s", p))
      }
   }()

   //处理参数
   params := make([]reflect.Value, 0)
   if args != nil {
      for i := 0; i < len(args); i++ {
         params = append(params, reflect.ValueOf(args[i]))
      }
   }

   //调用方法
   call := m.value.Call(params)

   //接收返回值
   res = make([]interface{}, 0)
   if call != nil && len(call) > 0 {
      for i := 0; i < len(call); i++ {
         res = append(res, call[i].Interface())
      }
   }
   return
}

测试

package pro

import (
   "fmt"
   "testing"
   "time"
)

func TestName(t *testing.T) {
   //这里对活动时长做统计
   people := &People{}   //创建目标类
   h := new(PeopleProxy) //创建接口实现类
   proxy := NewProxy(people, h)
   //调用方法
   ret, err := proxy.InvokeMethod("Work", "敲代码", "学习")
   if err != nil {
      fmt.Println(err)
   }

   fmt.Println(ret)
}

//目标类
type People struct {
}

func (p *People) Work(content string, next string) string {
   fmt.Println("活动内容是:" + content + ",接下来需要做:" + next)
   return "all right"
}

//用户需要自己实现的增强内容,需要实现InvocationHandler接口
type PeopleProxy struct {
}

//在这里做方法增强
func (p *PeopleProxy) Invoke(proxy *Proxy, method *Method, args []interface{}) ([]interface{}, error) {
   start := time.Now()
   defer fmt.Printf("耗时:%v\n", time.Since(start))
   fmt.Println("before method")
   invoke, err := method.Invoke(args...)
   fmt.Println("after method")
   return invoke, err
}

输出

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9hKFwyme-1659607080908)(C:/Users/86158/AppData/Roaming/Typora/typora-user-images/image-20220804175747463.png)]

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,关于 Java JDK 动态代理的代码,你可以参考以下示例: ``` public interface HelloWorld { void sayHello(); } public class HelloWorldImpl implements HelloWorld { @Override public void sayHello() { System.out.println("Hello World!"); } } public class HelloWorldHandler implements InvocationHandler { private Object target; public HelloWorldHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = method.invoke(target, args); return result; } } public class Main { public static void main(String[] args) { HelloWorld helloWorld = new HelloWorldImpl(); HelloWorldHandler handler = new HelloWorldHandler(helloWorld); HelloWorld proxy = (HelloWorld) Proxy.newProxyInstance( helloWorld.getClass().getClassLoader(), helloWorld.getClass().getInterfaces(), handler); proxy.sayHello(); } } ``` 这段代码演示了如何使用 Java JDK 动态代理来代理一个接口实现类,并在代理对象的方法调用前后添加额外的逻辑,例如打印日志。在这个示例中,我们定义了一个 `HelloWorld` 接口及其实现类 `HelloWorldImpl`,然后定义了一个 `HelloWorldHandler` 类来实现 `InvocationHandler` 接口,它的作用是在代理对象的方法调用前后打印日志。最后,在 `Main` 类中,我们使用 `Proxy.newProxyInstance()` 方法来创建代理对象,并将其强制转换为 `HelloWorld` 接口类型,从而实现对 `HelloWorldImpl` 的代理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值