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

动态代理

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

JDK 动态代理

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* loader: 类加载器
* interfaces: 被代理对象实现的一些接口
* h: 实现了InvocationHandler接口的对象
*/
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
......
}

/**
* proxy: 动态生成的代理类
* method: 与代理类对象调用的方法相对应
* args: 当前method方法的参数
*/
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throw Throwable;
}

过程

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

实例

以发送短信为例:

  1. 定义发送短信的接口

    1
    2
    3
    4
    5
    6
    7
    /**
    * 发送短信的接口
    */

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /**
    * 实现接口
    */

    public class SmsServiceImpl implements SmsService {
    @Override
    public String send(String message) {
    System.out.println("send " + message);
    return message;
    }
    }
  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
    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() {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("proxy send " + args[0]);
    return method.invoke(target, args);
    }
    }
    );
    }

    // 代理接口
    public static Object getInterfaceProxy(Class<?> inter) {
    ClassLoader classLoader = inter.getClassLoader();
    Class<?>[] interfaces = new Class[]{inter};
    return Proxy.newProxyInstance(
    classLoader,
    interfaces,
    new InvocationHandler() {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println(method.getName());
    return "None";
    }
    }
    );
    }
    }

    我们使用动态代理对象调用原对象的原生方法时,实际上是通过 invoke() 方法去调用被代理对象的原生方法。

  4. 使用动态代理类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    SmsService smsServiceimpl = (SmsService) ProxyFactory.getProxy(new SmsServiceImpl());
    smsServiceimpl.send("new value");
    // out:
    // proxy send new value
    // send new value

    SmsService smsServiceimpl = (SmsService) ProxyFactory.getInterfaceProxy(SmsService.class);
    // out:
    // send

CGLIB 动态代理

CGLIB 通过生成一个被代理类的子类来拦截被代理类的方法调用。核心是 MethodInterceptor 接口和Enhancer 类。使用前需要添加依赖:

1
2
3
4
5
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>

过程

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

实例

同样的发短信为例:

  1. 实现类

    1
    2
    3
    4
    5
    6
    public class AliSmsService {
    public String send(String message) {
    System.out.println("send message:" + message);
    return message;
    }
    }
  2. 自定义 MethodInterceptor

    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
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;

    import java.lang.reflect.Method;

    /**
    * 自定义MethodInterceptor
    */
    public class DebugMethodInterceptor implements MethodInterceptor {


    /**
    * @param o 代理对象(增强的对象)
    * @param method 被拦截的方法(需要增强的方法)
    * @param args 方法入参
    * @param methodProxy 用于调用原始方法
    */
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    //调用方法之前,我们可以添加自己的操作
    System.out.println("before method " + method.getName());
    Object object = methodProxy.invokeSuper(o, args);
    //调用方法之后,我们同样可以添加自己的操作
    System.out.println("after method " + method.getName());
    return object;
    }

    }
  3. 获取代理类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import net.sf.cglib.proxy.Enhancer;

    public class CglibProxyFactory {

    public static Object getProxy(Class<?> clazz) {
    // 创建动态代理增强类
    Enhancer enhancer = new Enhancer();
    // 设置类加载器
    enhancer.setClassLoader(clazz.getClassLoader());
    // 设置被代理类
    enhancer.setSuperclass(clazz);
    // 设置方法拦截器
    enhancer.setCallback(new DebugMethodInterceptor());
    // 创建代理类
    return enhancer.create();
    }
    }
  4. 使用

    1
    2
    3
    4
    5
    6
    7
    AliSmsService aliSmsService = (AliSmsService) CglibProxyFactory.getProxy(AliSmsService.class);
    aliSmsService.send("java");

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

JDK 动态代理和 CGLIB 动态代理比较

  1. JDK 动态代理只能代理接口实现类或者接口。
  2. CGLIB 可以代理未实现任何接口的类,但是该类不能声明为 final。
  3. JDK 的动态代理效率更高,优势明显。

静态代理

静态代理实际应用的场景很少,日常几乎不使用静态代理。

过程

  1. 定义一个接口及其实现类;
  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
public static class SmsServiceProxy implements SmsService {
public SmsServiceImpl smsServiceimpl;

public SmsServiceProxy(SmsServiceImpl smsServiceimpl) {
this.smsServiceimpl = smsServiceimpl;
}

@Override
public String send(String message) {
System.out.println("proxy send " + message);
smsServiceimpl.send(message);
return message;
}
}

public static class SmsServiceImpl implements SmsService {
@Override
public String send(String message) {
System.out.println("send " + message);
return message;
}
}

public interface SmsService {
String send(String message);
}

public static void main(String[] args) {
SmsServiceImpl smsServiceimpl = new SmsServiceImpl();
SmsService smsServiceProxy = new SmsServiceProxy(smsServiceimpl);
smsServiceProxy.send("new message");
}

// out:
// proxy send new message
// send new message

参考

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