# 简介

代理模式可以创造代理对象,替代对真实对象的访问。目的是在不修改原对象的前提下,扩展目标对象并提供额外的功能操作。
代理模式主要分为动态代理和静态代理两种实现方式。

# 动态代理

动态代理是在 JVM 运行时动态生成字节码,并加载到 JVM 中的。

| JDK 动态代理

在 Java 动态代理机制中,InvocationHandler 和 Proxy 类是核心。

* 过程

  1. 定义接口和接口实现类;
  2. 通过 Proxy.newProxyInstance() 方法创建代理对象;
  3. 重写 InvocationHandler 中的 invoke() 方法,自定义一些处理逻辑;

    * 实例

    以发送短信为例:

  4. 定义发送短信的接口

    1. public interface SmsService {
    2. String send(String message);
    3. }
  5. 实现发送短信的接口

    1. public class SmsServiceImpl implements SmsService {
    2. @Override
    3. public String send(String message) {
    4. System.out.println("send " + message);
    5. return message;
    6. }
    7. }
  6. 定义生成代理对象的工厂类 ```java import java.lang.reflect.*;

public static class ProxyFactory { // 代理接口的实现类 public static Object getProxy(Object target) { return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { /*

  1. * @param proxy: 生成的动态代理类
  2. * @param method: 和代理类对象调用的方法对应;
  3. * @param args:当前method方法的参数
  4. */
  5. @Override
  6. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  7. System.out.println("proxy send " + args[0]);
  8. return method.invoke(target, args);
  9. }
  10. }
  11. );
  12. }
  13. // 代理接口
  14. public static Object getInterfaceProxy(Class<?> inter) {
  15. ClassLoader classLoader = inter.getClassLoader();
  16. Class<?>[] interfaces = new Class[]{inter};
  17. return Proxy.newProxyInstance(
  18. classLoader,
  19. interfaces,
  20. new InvocationHandler() {
  21. @Override
  22. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  23. System.out.println(method.getName());
  24. return "None";
  25. }
  26. }
  27. );
  28. }

}

  1. 我们使用动态代理对象调用原对象的原生方法时,实际上是通过 invoke() 方法去调用被代理对象的原生方法。
  2. 4. 使用动态代理类
  3. ```java
  4. SmsService smsServiceimpl = (SmsService) ProxyFactory.getProxy(new SmsServiceImpl());
  5. smsServiceimpl.send("new value");
  6. // out:
  7. // proxy send new value
  8. // send new value
  9. SmsService smsServiceimpl = (SmsService) ProxyFactory.getInterfaceProxy(SmsService.class);
  10. // out:
  11. // send

| CGLIB 动态代理

CGLIB 通过生成一个被代理类的子类来拦截被代理类的方法调用。核心是 MethodInterceptor 接口和Enhancer 类。

* 过程

  1. 定义一个类;
  2. 定义 MethodInterceptor 方法并重写 intercept(),intercept 用于拦截增强被代理类的方法,和 JDK 动态代理中的 invoke() 类似;
  3. 通过 Enhancer 类的 create() 创建代理类;

    * 实例

    同样的发短信为例:

  4. 实现类

    1. public class AliSmsService {
    2. public String send(String message) {
    3. System.out.println("send message:" + message);
    4. return message;
    5. }
    6. }
  5. 自定义 MethodInterceptor ```java import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**

  • 自定义MethodInterceptor */ public class DebugMethodInterceptor implements MethodInterceptor {
  1. /**
  2. * @param o 代理对象(增强的对象)
  3. * @param method 被拦截的方法(需要增强的方法)
  4. * @param args 方法入参
  5. * @param methodProxy 用于调用原始方法
  6. */
  7. @Override
  8. public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
  9. //调用方法之前,我们可以添加自己的操作
  10. System.out.println("before method " + method.getName());
  11. Object object = methodProxy.invokeSuper(o, args);
  12. //调用方法之后,我们同样可以添加自己的操作
  13. System.out.println("after method " + method.getName());
  14. return object;
  15. }

}

  1. 3. 获取代理类
  2. ```java
  3. import net.sf.cglib.proxy.Enhancer;
  4. public class CglibProxyFactory {
  5. public static Object getProxy(Class<?> clazz) {
  6. // 创建动态代理增强类
  7. Enhancer enhancer = new Enhancer();
  8. // 设置类加载器
  9. enhancer.setClassLoader(clazz.getClassLoader());
  10. // 设置被代理类
  11. enhancer.setSuperclass(clazz);
  12. // 设置方法拦截器
  13. enhancer.setCallback(new DebugMethodInterceptor());
  14. // 创建代理类
  15. return enhancer.create();
  16. }
  17. }
  1. 使用 ```java AliSmsService aliSmsService = (AliSmsService) CglibProxyFactory.getProxy(AliSmsService.class); aliSmsService.send(“java”);

// out // before method send // send message:java // after method send

  1. <a name="ASbnl"></a>
  2. ## | JDK 动态代理和 CGLIB 动态代理比较
  3. 1. JDK 动态代理只能代理接口实现类或者接口。
  4. 1. CGLIB 可以代理未实现任何接口的类,但是该类不能声明为 final。
  5. 1. JDK 的动态代理效率更高,优势明显。
  6. <a name="HanXp"></a>
  7. # # 静态代理
  8. 静态代理实际应用的场景很少,日常几乎不使用静态代理。
  9. <a name="MEx6d"></a>
  10. ## * 过程
  11. 1. 定义一个接口及其实现类;
  12. 1. 创建一个代理类同样实现接口;
  13. 1. 将目标对象注入进代理类,在代理类中调用目标类的对应方法。
  14. <a name="x2tbe"></a>
  15. ## * 实例
  16. ```java
  17. public static class SmsServiceProxy implements SmsService {
  18. public SmsServiceImpl smsServiceimpl;
  19. public SmsServiceProxy(SmsServiceImpl smsServiceimpl) {
  20. this.smsServiceimpl = smsServiceimpl;
  21. }
  22. @Override
  23. public String send(String message) {
  24. System.out.println("proxy send " + message);
  25. smsServiceimpl.send(message);
  26. return message;
  27. }
  28. }
  29. public static class SmsServiceImpl implements SmsService {
  30. @Override
  31. public String send(String message) {
  32. System.out.println("send " + message);
  33. return message;
  34. }
  35. }
  36. public interface SmsService {
  37. String send(String message);
  38. }
  39. public static void main(String[] args) {
  40. SmsServiceImpl smsServiceimpl = new SmsServiceImpl();
  41. SmsService smsServiceProxy = new SmsServiceProxy(smsServiceimpl);
  42. smsServiceProxy.send("new message");
  43. }
  44. // out:
  45. // proxy send new message
  46. // send new message

# 参考

  1. java动态代理—代理接口无实现类