跳转至
#java  #spring 
本文阅读量 

代理模式#

为什么要学习代理模式#

代理模式是SpringAOP的底层

代理模式的分类#

  • 静态代理
  • 动态代理

静态代理#

角色分析
- 抽象接口:真实类和代理类都要实现的接口
- 真实类:被代理的类
- 代理类:代理真实类,一般代理后会有一些附属操作
- 客户类:访问代理类

实例代码#

package top.longlone;

public interface Rent {
    public void rent();
}

package top.longlone;

public class Landlord implements Rent {
    public void rent(){
        System.out.println("租房子");
    }
}
````
```java
package top.longlone;

public class LandlordProxy implements Rent {
    public Rent landlord;

    public LandlordProxy() {
        this.landlord = new Landlord();
    }

    public void rent() {
        this.landlord.rent();
        System.out.println("收中介费");
    }

}
````
```java
package top.longlone;

public class Client {
    public static void main(String[] args) {
        Rent landlordProxy = new LandlordProxy();
        landlordProxy.rent();
    }
}

代理模式的特点#

优点:
- 可以使真实类更加纯粹,不再需要关注一些公共服务
- 实现公共服务交给代理角色,实现了业务分工
- 客户类只能访问到代理类,隐藏了真实类
- 方便扩展和集中管理
缺点:
- 代理类和真实类的关系在编译时确定,所以一个真实类就需要一个代理类

动态代理#

动态代理分为两类:基于接口的动态代理和基于类的动态代理
- 基于接口: JDK动态代理
- 基于类: cglib
- java字节码实现: javasist

这里先了解JDK自带的动态代理
需要了解2个类:
- Proxy:用于创建代理类的类
- InvocationHandler:代理实例调用方法时的一个接口,通过在invoke方法里编写额外代码实现附属功能

实例代码#

package top.longlone;

// 抽象接口,抽象出rent这个方法
public interface Rent {
    public void rent();
}

package top.longlone;

// 真实类,实现了rent方法
public class Landlord implements Rent {
    public void rent(){
        System.out.println("租房子");
    }
}

package top.longlone;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 这里将Porxy和InvocationHandler合二为一
public class LandlordInvocationHandler implements InvocationHandler {
    //真实类的实例,即被代理的实例
    private Object obj;

    public Object getObj() {
        return obj;
    }

    public void setObj(Object obj) {
        this.obj = obj;
    }

    public LandlordInvocationHandler() {
    }

    public LandlordInvocationHandler(Object obj) {
        this.obj = obj;
    }

    // 获取代理类
       public Rent getProxy() {
        return (Rent) Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
    }

    // 重写InvocationHandler的invoke方法,在调用Rent接口的任何方法前前增加一句输出
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Running method: " + method.getName());
        Object result = method.invoke(obj, args);
        return result;
    }
}

package top.longlone;

public class Client {
    public static void main(String[] args) {
        // 创建真实类的实例,即被代理的实例
        Landlord landlord = new Landlord();
        // 创建自己编写的InvocationHandler,并传入被代理的实例
        LandlordInvocationHandler handler = new LandlordInvocationHandler(landlord);
        // 获取代理类
        Rent landlordProxy = handler.getProxy();
        // 调用代理类的rent方法
        landlordProxy.rent();
        /* Output:
        Running method: rent
        租房子
        */
    }
}

代理模式和装饰器模式的区别#

装饰器模式关注于在一个对象上动态的添加方法,然而代理模式关注于控制对对象的访问。换句话 说,用代理模式,代理类可以对它的客户隐藏一个对象的具体信息。因此,当使用代理模式的时候,我们常常在一个代理类中创建一个对象的实例。并且,当我们使用装饰器模 式的时候,我们通常的做法是将原始对象作为一个参数传给装饰者的构造器。
使用代理模式,代理和真实对象之间的的关系通常在编译时就已经确定了,而装饰者能够在运行时递归地被构造。

总结#

代理模式是SpringAOP的底层,分为静态代理和动态代理,同时了解了JDK自带的动态代理的编写。

回到页面顶部