代理模式的理解和实例

是什么?作用?

  1. 定义:为另一个对象提供一个替身或占位符以控制对这个对象的访问 (控制访问)
  2. 分类
    • 远程代理: 有点类似dubbo,调用代理的方法,会被代理利用网络转发到远程执行,并把结果通过网络返回给代理,最后返回给客户
    • 虚拟代理: 作为创建开销大对象的代表,一般等该对象创建成功后,在委托给改对象
    • 安全代理: 控制访问权限
    • 智能代理: 提供对目标对象的额外服务
  3. 实现代理的方式
    • 动态代理:利用反射在运行时创建代理类,并将方法的调用转发到你所指定的类
    • 静态代理:代理类是运行之前就被创建出来了,相对于动态代理
  4. 动态代理实现方式分类
    • JDK动态代理
    • CGLIB动态代理
  5. 使用场景
      AOP、防火墙、缓存、同步、。。。
  6. 类图
    代理模式类图
  • Subject抽象主体角色: 可以是抽象类或者是接口
  • RealSubject 具体的主体: 业务的真正执行者
  • Proxy 代理类: 作为主题的代理类,通过访问代理类,来访问真正的主题类

代理示例

静态代理

代理背景: 假设我要去屈臣氏买点洗漱用品,我一哥们要出去买东西,所以就让他帮我买了

  1. Subject

    1
    2
    3
    4
    5
    6
    7
    /**
    * 买洗漱用品接口
    */
    public interface BuyCosmetics {

    void shop();
    }
  2. 在屈臣氏可以买

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    /**
    * 屈臣氏
    */
    public class Watsons implements BuyCosmetics{

    @Override
    public void shop() {
    System.out.println("在屈臣氏买化妆品");
    }
    }
  3. 让兄弟帮我买

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    /**
    * 我朋友帮忙跑一趟
    */
    public class MyFriend implements BuyCosmetics {

    private Watsons watsons;

    public MyFriend(Watsons watsons) {
    this.watsons = watsons;
    }

    @Override
    public void shop() {
    watsons.shop();
    }
    }
  4. 测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /**
    * 测试类
    */
    public class Main {

    public static void main(String[] args) {
    Watsons watsons = new Watsons();
    MyFriend myFriend = new MyFriend(watsons);
    myFriend.shop();
    }
    }

这里实现了朋友帮我买东西的例子,和很多博客都不一样,所以如果有问题,清大家指出

JDK动态代理

使用java API实现动态代理,需要注意InvocationHandler接口, 它的作用是响应代理的任何调用,需要三步

  1. 创建代理调用处理器
  2. 实例化代理
  3. 通过代理调用行为

代码

  1. Subject
    同上

  2. 在屈臣氏可以买
    同上

  3. 创建代理调用处理器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    /**
    * 动态代理
    * 作用:
    * 1. 生成代理对象
    * 2. 指定需要代理的真实对象
    * 3. 调用真实对象的操作
    */
    public class DynamicProxy implements InvocationHandler {

    /**
    * 要代理的真实对象
    */
    private BuyCosmetics proxyObject;

    /**
    * 这个方法用来创建代理类,并实例化代理类
    */
    public BuyCosmetics getProxy(BuyCosmetics proxyObject) {
    this.proxyObject = proxyObject;

    return (BuyCosmetics) Proxy.newProxyInstance(proxyObject.getClass().getClassLoader(),
    proxyObject.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // 利用反射调用真实对象的方法, 可以在调用前后添加你的业务
    Object result = method.invoke(proxyObject, args);

    return result;
    }
    }
  4. 测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class Main {

    public static void main(String[] args) {

    // 1. 创建调用处理器对象
    DynamicProxy dynamicProxy = new DynamicProxy();

    // 2. 创建真实对象
    Watsons watsons = new Watsons();

    // 3. 创建动态代理类 传入目标对象
    BuyCosmetics buyCosmetics = dynamicProxy.getProxy(watsons);

    // 4. 执行行为
    buyCosmetics.shop();
    }
    }

CGLIB动态代理

  1. Subject
    同上

  2. 在屈臣氏可以买
    同上

  3. 创建代理调用处理器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;

    import java.lang.reflect.Method;

    /**
    * 代理调用处理器
    */
    public class DynamicProxy implements MethodInterceptor {

    private Enhancer enhancer;

    public Object getProxy(Class clazz) {
    enhancer = new Enhancer();

    // 设置需要代理的类
    enhancer.setSuperclass(clazz);
    //设置需要代理的类
    enhancer.setCallback(this);

    // 用于创建无参的目标对象代理类,对于有参构造器则调用Enhancer.create(Class[] argumentTypes, Object[] arguments),第一个参数表示参数类型,第二个参数表示参数的值
    return enhancer.create();
    }

    /**
    *
    * @param o Subject类, 即被代理的类
    * @param method Method表示拦截的方法
    * @param objects 被代理类的参数
    * @param methodProxy MethodProxy表示对方法的代理,invokeSuper方法表示对被代理对象方法的调用
    */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    System.out.println("调用前");
    Object result = methodProxy.invokeSuper(o, objects);
    System.out.println("调用后");

    return result;
    }
    }
  4. 测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    /**
    * cglib动态代理 test
    */
    public class MainClient {

    public static void main(String[] args) {
    DynamicProxy dynamicProxy = new DynamicProxy();
    BuyCosmetics watsons = (Watsons)dynamicProxy.getProxy(Watsons.class);

    watsons.shop();
    System.out.println(watsons.getClass().getName());
    }
    }
  5. 结果
    调用前
    在屈臣氏买化妆品
    调用后
    com.example.demo.代理模式.CGLIB动态代理.Watsons$$EnhancerByCGLIB$$2f4d9538

总结

  1. 代理模式使用最多的就是,智能代理, 会为被代理对象提供额外的服务
  2. 类图和装饰器模式很像,主要看使用的目的,还有装饰器一般持有的是基类,而代理一般持有的具体的类
  3. 优点:
      - 良好的扩展性。修改被代理角色并不影响调用者使用代理,对于调用者,被代理角色是透明的。
      - 隔离,降低耦合度。代理角色协调调用者和被代理角色,被代理角色只需实现本身关心的业务,非自己本职的业务通过代理处理和隔离。
  4. 缺点:
      - 访问时间可能延长
      - 类数量增加