一、类型

结构型设计模式

二、代理模式的定义

代理模式 是指为其他对象提供一种代理, 以控制对这个对象的访问.

代理对象在客户端和目标对象之间起到中介作用.

三、静态代理和动态代理区别

静态代理: 硬编码、手动注入, 手动拿到目标对象的引用, 手动调用代理目标的方法.

动态代理: 具有更强的扩展性, 自动注入, 自动生成一个新的类(同一个继承体系)

特征:

1.拿到代理目标对象的引用  
2.实现功能增强  
3.保护目标对象 

四、动态代理对象的创建过程

  1. 动态拼接出代理对象的java类的代码(包括java类的import xxx、类名、构造方法、继承接口、方法等动态拼接出来形成一个正常的java类)
  2. 用文件流将代理对象的java类输出到磁盘, 保存为$Proxy0.java文件
  3. 将$Proxy0.java文件进行编译成.class文件, 新文件为$Proxy0.class
  4. 将生成的$Proxy0.class加载到JVM内存中
  5. 返回新的代理对象

五、CgLib Proxy 与 JDK Proxy 区别

  • 不同点:

    1. CgLib Proxy 使用继承的方式, 覆盖父类的方法.
    2. JDK Proxy 采用实现接口的方式, 必须要求代理的目标实现一个接口.
    3. CgLib Proxy 对目标类没有任何要求.
    4. JDK Proxy 对于用户而言, 依赖更强, 调用更复杂.
    5. CgLib Proxy 采用另外一套API, 没有使用反射, 性能更高.
    6. JDK Proxy 生成逻辑较为简单, 执行效率相对较低, 每次都使用到反射.
  • 相同点:

    1. 都是通过生成字节码, 重组成一个新的类.
  • CgLib 有个坑:

    1. 由于使用的继承, 目标代理类不能有final修饰的方法, 他会忽略final修饰的方法.

六、代理模式优点

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

七、代理模式缺点

  1. 代理模式会造成系统设计中类数量增加.
  2. 在客户端和目标对象之前增加了一个代理对象, 会降低请求速度.
  3. 增加系统复杂度

八、Spring 中的代理选择原则

  1. 当 Bean 有实现接口时, Spring 就会使用 JDK 的动态代理.
  2. 当 Bean 没有实现接口时, Spring 会选择 CGLib.
  3. Spring 可以通过配置强制使用 CGLib, 只需在 Spring 配置文件中加入以下代码:

    <aop:aspectj-autoproxy proxy-target-class='true'/>

九、JDK 动态代理的使用

public class MyProxy implements InvocationHandler {

    // 目标对象接口
    private IPerson target;

    public IPerson getInstance(IPerson target){
        this.target = target;
        Class<? extends IPerson> clazz = target.getClass();
        return (IPerson) Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object invoke = method.invoke(this.target, args);
        after();
        return invoke;
    }

    private void before(){
        System.out.println("before()...");
    }

    private void after(){
        System.out.println("after()...");
    }
}
public static void main(String[] args){

    MyProxy proxy = new MyProxy();
    IPerson instance = proxy.getInstance(new Zhangsan());
    instance.doSomething();
    
}
执行结果
----------------------------------------------------------------------------------
before()...
张三正在执行某件事...
after()...
----------------------------------------------------------------------------------
最后修改:2022 年 06 月 23 日
如果觉得我的文章对你有用,请点个赞吧~