设计模式之代理模式

proxy design pattern

代理模式的概念、代理模式的结构、代理模式的优缺点、代理模式的使用场景、代理模式的实现示例(静态代理、jdk 动态代理、cglib 动态代理)、代理模式的源码分析


1、代理模式的概念

  代理模式,为某个对象提供一种代理以控制对对象的访问。即客户端可通过代理对象间接访问目标对象,同时可限制、增强、修改目标对象的一些特性。访问者不想或者不能直接访问目标对象,代理对象作为目标对象和访问者之间的中介。

2、代理模式的结构

  • 抽象目标:定义目标对象的行为。
  • 具体目标:实现抽象目标,实现其具体行为。
  • 代理类:实现抽象目标,拥有对具体目标的引用,同时可对目标对象进行增强处理。

proxy-class

3、代理模式的优缺点

  • 优点:
    • 代理对象在目标对象和访问者之间起到一个中介的作用,且可以保护目标对象。
    • 可以增强目标对象的功能。
    • 将访问者与目标对象分离,在一定程度上降低了系统的耦合度。
  • 缺点:
    • 当使用动态代理实现时,会使系统响应速度降低,因为其底层使用反射。
    • 增加代理对象或代理工厂会增加系统的复杂度。

4、代理模式的使用场景

  • 虚代理:当需要创建开销很大的对象时,只有用到才创建。
  • 保护代理:控制目标对象的访问。如过滤器、防火墙。
  • 智能指引:在访问对象时附加一些操作,如对象没有引用时释放资源。
  • 远程代理:为一个对象在不同的地址空间提供局部代理。也包括通信代理,如 vpn 等。

常见代理模式:

  • 防火墙代理:内网通过代理穿透防火墙,实现对公网的访问。
  • 缓存代理:当请求资源时,先从缓存中取,若没有,则再去数据库中取。
  • 远程代理:远程对象的本地代表,通过它可以把远程对象当作本地对象来调用。
  • 同步代理:主要在多线程间完成同步工作。

5、代理模式的实现示例

  代理模式共有两类三种实现方式,即静态代理和动态代理,同时动态代理则可以使用 jdk 动态代理和 cglib 动态代理实现。

  • 静态代理:代理类在编译期生成。

  • 动态代理:代理类在运行期生成。

    • jdk 动态代理:

      Java.lang.reflect 包中的 proxy 类和 InvocationHandler 接口提供了生成代理类的功能。jdk 动态代理有一个限制,那就是代理目标类必须实现一个或多个接口。

    • cglib 动态代理:

      cglib 是一个强大的高性能代码生成包,它可以在运行时扩展 java 类或实现 java 接口。被广泛应用于许多 aop 框架,如 spring aop 和 dynaop。其底层使用一个小而快的字节码处理框架 ASM,通过 asm 来转换字节码并生成类。

  jdk 动态代理与 cglib 动态代理区别:

  • 使用 jdk 代理的目标类必须实现一个或多个接口。使用 cglib 代理的目标类则无需实现,但其不能被 final 修饰,因为其运用了继承关系。
  • Jdk 1.8 以后 idk 动态代理效率要高于 cglib。
5.1、静态代理

抽象目标:

public interface Subject {

    /**
     * 定义目标类行为
     */
    void behavior();
}

具体目标类:

public class TargetSubject implements Subject {

    @Override
    public void behavior() {
        System.out.println("我是目标对象");
    }
}

代理类:

public class ProxySubject implements Subject {

    private Subject targetObject = new TargetSubject();

    @Override
    public void behavior() {
        System.out.println("前置加强处理");
        this.targetObject.behavior();
        System.out.println("后置加强处理");
    }
}

测试:

public class StaticProxyTest {

    public static void main(String[] args) {
        Subject proxy = new ProxySubject();
        proxy.behavior();
    }
}

测试结果:

前置加强处理
我是目标对象
后置加强处理
5.2、jdk 动态代理

抽象目标:

public interface Subject {

    /**
     * 定义目标类行为
     */
    void behavior();
}

具体目标类:

public class TargetSubject implements Subject {

    @Override
    public void behavior() {
        System.out.println("我是目标对象");
    }
}

代理类:

public class ProxyFactory {

    private Subject targetObject = new TargetSubject();

    /**
     * 获取代理对象
     * @return
     */
    public Subject getProxyObject() {
        return  (Subject) Proxy.newProxyInstance(
                targetObject.getClass().getClassLoader(),
                targetObject.getClass().getInterfaces(),
                ((proxy, method, args) -> {
                    System.out.println("前置加强处理");
                    Object o = method.invoke(targetObject, args);
                    System.out.println("后置加强处理");
                    return o;
                })
        );
    }
}

测试:

public class JdkProxyTest {

    public static void main(String[] args) {
        ProxyFactory factory = new ProxyFactory();
        Subject proxy = factory.getProxyObject();
        proxy.behavior();
    }
}

测试结果:

前置加强处理
我是目标对象
后置加强处理
5.3、cglib 动态代理

目标类:

public class TargetSubject {

    public void behavior() {
        System.out.println("我是目标对象");
    }
}

代理类:

public class ProxyFactory implements MethodInterceptor {

    private TargetSubject targetObject = new TargetSubject();

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("前置加强处理");
        Object o1 = method.invoke(targetObject, objects);
        System.out.println("后置加强处理");
        return o1;
    }

    /**
     * 获取代理对象
     * @return
     */
    public TargetSubject getProxyObject() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(TargetSubject.class);
        enhancer.setCallback(this);
        return (TargetSubject) enhancer.create();
    }
}

测试:

public class CglibProxyTest {

    public static void main(String[] args) {
        ProxyFactory factory = new ProxyFactory();
        TargetSubject proxy = factory.getProxyObject();
        proxy.behavior();
    }
}

测试结果:

前置加强处理
我是目标对象
后置加强处理

6、代理模式源码分析

  mybatis 中的 MapperRegistry 类中的 getMapper 方法即使用了 jdk 的动态代理实现的代理模式。

// 相当于于客户端
public class MapperRegistry {
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }
  ...
}
// 代理工厂
public class MapperProxyFactory<T> {

  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();

  public MapperProxyFactory(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
  }

  public Class<T> getMapperInterface() {
    return mapperInterface;
  }

  public Map<Method, MapperMethodInvoker> getMethodCache() {
    return methodCache;
  }

  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }
  ...
}
// 代理类
public class MapperProxy<T> implements InvocationHandler, Serializable {
  static {
    Method privateLookupIn;
    try {
      privateLookupIn = MethodHandles.class.getMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class);
    } catch (NoSuchMethodException e) {
      privateLookupIn = null;
    }
    privateLookupInMethod = privateLookupIn;

    Constructor<Lookup> lookup = null;
    if (privateLookupInMethod == null) {
      // JDK 1.8
      try {
        lookup = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
        lookup.setAccessible(true);
      } catch (NoSuchMethodException e) {
        throw new IllegalStateException(
            "There is neither 'privateLookupIn(Class, Lookup)' nor 'Lookup(Class, int)' method in java.lang.invoke.MethodHandles.",
            e);
      } catch (Exception e) {
        lookup = null;
      }
    }
    lookupConstructor = lookup;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else {
        return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
  }
  ...
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值