Fork me on GitHub

JDK动态代理

原理

  • 通过JDK的java.lang.reflect.Proxy类实现动态代理,使用其静态方法newProxyInstance(),依据目标对象,业务接口和业务逻辑增强三者动态生成代理对象。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    /**

    - @param loader the class loader to define the proxy class
    - 目标类的类加载器,通过目标对象的发射可获取
    - @param interfaces the list of interfaces for the proxy class
    - to implement
    - 目标类实现的接口数组,通过反射可获取
    - @param h the invocation handler to dispatch method invocations to
    - 业务增强逻辑,需要再定义
    - @return a proxy instance with the specified invocation handler of a
    - proxy class that is defined by the specified class loader
    - and that implements the specified interfaces
    */
    public static Object newProxyInstance(ClassLoader loader,
    Class<?>[] interfaces,
    InvocationHandler h)
  • InvocationHandler是个接口,实现该接口的类用于增强目标类的主业务逻辑。接口中定义了一个invoke()方法,具体加强的代码逻辑定义在该方法中。程序在调用主业务逻辑时自动调用invoke()方法。

    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
    /**

    * @param proxy the proxy instance that the method was invoked on

    * 生成的代理对象

    * @param method the {@code Method} instance corresponding to

    * the interface method invoked on the proxy instance. The declaring

    * class of the {@code Method} object will be the interface that

    * the method was declared in, which may be a superinterface of the

    * proxy interface that the proxy class inherits the method through.

    * 目标方法

    * @param args an array of objects containing the values of the

    * arguments passed in the method invocation on the proxy instance,

    * or {@code null} if interface method takes no arguments.

    * Arguments of primitive types are wrapped in instances of the

    * appropriate primitive wrapper class, such as

    * {@code java.lang.Integer} or {@code java.lang.Boolean}.

    * 目标方法的参数

    */

    public Object invoke(Object proxy, Method method, Object[] args)

    throws Throwable;

    由于该方法是由代理对象自动调用,所以三个参数不需程序员给出;

    第二个参数Method类对象,该类中也有一个方法invoke(),可以 调用目标类的目标方法 ,该方法的具体作用是:调用执行obj对象所属类的方法。

实现

  1. 定义业务接口,简单的转账业务

    1
    2
    3
    4
    5
    6
    7
    public interface IAccountService {

    //主业务逻辑,转账

    void transfer();

    }
  1. 定义目标类,该类实现业务接口,并实现接口定义的目标方法(只实现主业务逻辑转账)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class AccountServiceImpl implements IAccountService {

    //目标方法

    @Override

    public void transfer() {

    System.out.println("完成转账功能");

    }

    }
  1. 定义主业务增强逻辑类,该类需实现InvokeHandler接口,在invoke()方法中增加增强业务的代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class MyExtension implements InvocationHandler {

    //目标对象

    private Object target;
    //将目标对象引入,以便在invoke()中调用目标对象的目标方法
    public MyExtension(Object target) {
    this.target = target;
    }

    public MyExtension() {
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //增强业务逻辑的代码
    System.out.println("对转账人身份进行了验证!");
    //无论主业务方法有无参数,有无返回值,下面的写法均可兼顾到
    return method.invoke(target, args);
    }
    }
  1. 定义客户类

    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
    public class Client {

    public static void main(String[] args) {

    //定义目标对象

    IAccountService target = new AccountServiceImpl();

    //创建代理对象,并使用目标对象对其初始化

    IAccountService proxy = (IAccountService) Proxy.newProxyInstance(

    target.getClass().getClassLoader(),

    target.getClass().getInterfaces(),

    new MyExtension(target)

    );

    //执行增强业务之后的方法

    proxy.transfer();

    }
    }
-------------本文结束感谢您的阅读-------------