JDK动态代理技术

JDK 动态是java原生自带的,区别于Cglib动态代理(Cglib动态代理已经集成到Spring-Core下了)| JDK 动态代理要求:目标类必须要有接口,通过接口生成一个代理类;

来看下jdk动态代理的实现方式:
原先的业务

  • Calculator.java
package com.example;

/**
 * 计算器接口
 */
public interface Calculator {
    /**业务方法**/
    public int add(int i, int j);

    public int sub(int i, int j);

    public float divide(int i, int j);

    public int multi(int i, int j);
}
  • CalculatorImpl.java
package com.example;

public class CalculatorImpl implements Calculator {
    @Override
    public int add(int i, int j) {
        // 想打印输出参数

        // 核心方法处理业务
        int result = i + j;

        // 想打印输出结果
        return result;
    }

    @Override
    public int sub(int i, int j) {
        // 想打印输出参数

        // 核心方法处理业务
        int result = i - j;

        // 想打印输出结果
        return result;
    }

    @Override
    public float divide(int i, int j) {
        // 想打印输出参数

        // 核心方法处理业务
        int result = i / j;

        // 想打印输出结果
        return result;
    }

    @Override
    public int multi(int i, int j) {
        // 想打印输出参数

        // 核心方法处理业务
        int result = i * j;

        // 想打印输出结果
        return result;
    }
}

  • JDKProxyFactory.java
package com.example.dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

/**
 * JDK 动态代理
 */
public class JDKProxyFactory {

    private Object target;

    public JDKProxyFactory(Object target) {
        this.target = target;
    }

    /**
     * newProxyInstance(): 创建一个代理实例
     * 其中有三个参数:
     * 1、classLoader:加载动态生成的代理类的类加载器
     * 2、interfaces:目标对象实现的所有接口的class对象所铸成的数组
     * 3、invocationHandler:设置代理对象实现目标对象方法的过程,即代理类中如何重写接口中的抽象方法
     */
    public Object getProxy() {
        ClassLoader classLoader = target.getClass().getClassLoader();
        Class<?>[] interfaces = target.getClass().getInterfaces();
        InvocationHandler invocationHandler = new InvocationHandler() {

            /**
             * invoke: 调用代理的方法都会执行此类方法,非核心业务 + 目标调用就行了
             * proxy: 代理对象
             * method: 代理对象需要实现的方法,即其中需要重写的方法
             * args: method所对应方法的参数
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object result = null;
                try {
                    System.out.println("[动态代理][日志] " + method.getName() + " ,参数: " + Arrays.toString(args));
                    // 通过反射调用目标方法进行核心业务
                    result = method.invoke(target, args);
                    System.out.println("[动态代理][日志] " + method.getName() + " ,结果: " + result);
                } catch (Exception e) {
                    e.printStackTrace();
                    System.out.println("[动态代理][日志] " + method.getName() + " ,异常: " + e.getMessage());
                } finally {
                    System.out.println("[动态代理][日志] " + method.getName() + " ,方法执行完毕...");
                }
                return result;
            }
        };

        /**
         * JDK生成代理对象
         * 参数1:类加载器
         * 参数2:目标类的接口们
         * 参数3:具体要进行的代理动作【非核心动作,调用目标方法】
         */
        return Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
    }
}

  • 测试
package com.example;

import com.example.dynamic.JDKProxyFactory;

public class Main {
    public static void main(String[] args) {
        /**
         * JDK 动态代理测试
         * 观察 JDKProxyFactory 类,发现需要new一个实例,然后调用它的proxy方法即可;
         * 但是在new JDKProxyFactory构造时需要传入一个目标类
         * 注意:因为JDK动态代理对象是通过接口来生成目标代理对象,因此必须先有一个目标接口
         * 此种方式:即相当于我们把原先 CalculatorImpl 实现类中的额外功能 添加到 JDKProxyFactory 中了。
         */
        // 1、构造Calculator目标类,这个相当于我们原先已有的业务实现逻辑对象
        Calculator calculator = new CalculatorImpl();
        // 2. 构造 JDKProxyFactory JDK 动态代理工厂方法
        JDKProxyFactory proxyFactory = new JDKProxyFactory(calculator);
        // 3. 调用 getProxy 创建一个代理实例,此处即 Calculator 的代理实例,
        // 注意:此处一定要用 Calculator 接口来接收值,因为 getProxy 方法返回的是我们的 代理对象,不是目标对象(是我们目标对象的拜把子)
        // 即相当于是我们接口的 另外一个实现类
        Calculator calculatorProxy = (Calculator) proxyFactory.getProxy();
        // 4. 通过动态代理生成的Calculator的代理对象去 代替 调用它的目标方法
        calculatorProxy.add(3, 15);
    }
}

posted @ 2023-10-26 14:58  LoremMoon  阅读(4)  评论(1编辑  收藏  举报