深入了解JDK动态代理

什么是JDK动态代理

        (有动态代理,就有静态代理,参见:多线程03--静态代理模式_runnable接口静态代理模式-优快云博客

        JDK动态代理是Java提供的一种动态生成代理对象的机制,允许在运行时创建一个实现了指定接口的代理类。它主要用于在不修改目标对象的情况下,为目标对象添加额外的功能,比如日志记录、权限检查、事务管理等。

编码实现

        代码比较简单,但核心的步骤及实现细节都有,主要分析在后面。

定义一个顶层接口

package com.ldzn.normal.proxy.dynamic;

/**
 * @FileName: IService
 * @Description: 基类接口
 * @Author: liulianglin
 * @Date: 2024/11/26:11:32
 */
public interface IService {
    void myselfMethod();
}

被代理的对象

package com.ldzn.normal.proxy.dynamic;

/**
 * @FileName: RealObjectService
 * @Description: 真的对象服务
 * @Author: liulianglin
 * @Date: 2024/11/26:11:33
 */
public class RealObjectService implements IService{

    @Override
    public void myselfMethod() {
        System.out.println("RealObjectService test .......");
    }

}

自定义个动态代理处理类

package com.ldzn.normal.proxy.dynamic;

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

/**
 * @FileName: DynamicInvocationHandler
 * @Description: 动态代理处理类
 * @Author: liulianglin
 * @Date: 2024/11/26:11:34
 *
 *   1.拿到被代理对象的引用,然后获取它的接口
 *   2.jdk代理重新生成一个类,同时实现我们个额的代理对象所实现的接口
 *   3.把被代理对象的引用也拿到了
 *   4.重新动态生成一个class字节码
 *   5.然后编译
 *
 */
public class DynamicInvocationHandler implements InvocationHandler {
    private Object target;

    public Object getInstance(IService target) throws Exception {
        this.target = target;
        Class clazz = target.getClass();
        System.out.println("被代理对象的class是:"+ clazz);
        return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);

    }



    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("开始进行方法增强,(记录日志、校验、性能统计等),,,,");
        Object result = method.invoke(target, args);
        System.out.println("方法增强完毕,(记录日志、校验、性能统计等),,,,,");
        return result;
    }
}

测试调用

package com.ldzn.normal.proxy.dynamic;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @FileName: MainTest
 * @Description:
 * @Author: liulianglin
 * @Date: 2024/11/26:12:10
 */
public class MainTest {

    public static void printClassInfo(Executable[] targets) {
        for (Executable target : targets) {
            // 构造器/方法名称
            String name = target.getName();
            StringBuilder sBuilder = new StringBuilder(name);
            // 拼接左括号
            sBuilder.append('(');
            Class<?>[] clazzParams = target.getParameterTypes();
            // 拼接参数
            for (Class<?> clazzParam : clazzParams) {
                sBuilder.append(clazzParam.getName()).append(',');
            }
            //删除最后一个参数的逗号
            if (clazzParams.length != 0) {
                sBuilder.deleteCharAt(sBuilder.length() - 1);
            }
            //拼接右括号
            sBuilder.append(')');
            //打印 构造器/方法
            System.out.println(sBuilder.toString());
        }
    }

    /**
     * 将动态代理生成的代理类的字节码保存到本地磁盘,方便调试查看
     * @param path
     * @throws ClassNotFoundException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     * @throws IOException
     */
    public static void saveProxyClassFile(String path)  {

        Class cl = null;
        FileOutputStream fileOutputStream = null;
        try {
            // Java11开始ProxyGenerator,不再public,改为了private,无法直接使用,所以采用反射的方式获取它
            cl = Class.forName("java.lang.reflect.ProxyGenerator");

            Method m =cl.getDeclaredMethod("generateProxyClass",String.class,Class[].class);
            m.setAccessible(true);
            byte[] $proxy1 = (byte[]) m.invoke(null, "$proxy1",
                    RealObjectService.class.getInterfaces());
            System.out.println($proxy1.length);

            fileOutputStream = new FileOutputStream((path + "$Proxy.class"));
            fileOutputStream.write($proxy1);
        }catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            if (fileOutputStream !=
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值