设计模式之代理模式(二)

112 阅读2分钟

一、前言

在前一篇《设计模式之代理模式(一)》中,我们了解到了什么是代理,以及代理的三个特点或必要条件:

  • 必须包含两个角色:执行者和被代理人
  • 被代理人中的任务必须执行
  • 执行者中需要引用被代理人的资料信息即被代理人的引用。

同时,我们也使用了JDK自带的代理来实现了一个小Demo。不过由于代理最底层是一个字节码重组的过程,而且JDK的代理要求我们必须首先定义一个接口,还有就是性能上的局限性等,我们需要寻找更好的一种方式。

目前主流的还是基于第三方库cglib,所以需要我们在项目中引入第三方依赖cglib:cglib:版本

二、CGLib

2.1 介绍

cglib是一个强大的,高性能和高质量的代码生成库。它用于在运行时扩展Java类【即继承父类】和实现接口。同时他也是免费的开源库。

2.2 分析

与JDK代理中定义接口不同,CGLib只需要定义一个代理类,CGLib内部会自动生成一个他的子类,且子类会重写该代理类中的非 final 方法。

2.3 应用

目前使用最广的 Spring AOP 中的代理就是基于 CGLib。

2.4 结构图

2022-06-15-23-33-13-image.png

三、代码实践

3.1 创建代理类

根据上面的介绍,我们直接创建一个代理类,并实现其需要做的工作:

public class Developer {
    public void helloWorld() {
        System.out.println("开发人员写了一段 Hello World 的代码...");
    }
}

3.2 创建执行者

// 这里有个拦截器的概念
public class DeveloperProxy implements MethodInterceptor {

    public Object getInstance(Class superClass) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(superClass);
        enhancer.setCallback(this);

        return enhancer.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 这里需要注意,需要调用代理的父类方法
        methodProxy.invokeSuper(obj, args);
        return null;
    }
}

3.3 测试

public class DeveloperProxyMain {
    public static void main(String[] args) {
        Developer developer = (Developer) new DeveloperProxy().getInstance(Developer.class);
        System.out.println("代理类型:" + developer.getClass().getName());
        developer.helloWorld();
    }
}

观察结果:代理类型:com.hz.design.mode.proxy.cglib.Developer$$EnhancerByCGLIB$$a07de3f5

我们可以看到真正执行 helloWorld 方法的对象类型为 Developer$$EnhancerByCGLIB$$a07de3f5

同样的,参考上一篇,我们可以将其输出到磁盘,并反编译查看生成的子类信息。