自定义手写JDK动态代理

2023-05-16

前言

根据Java Porxy 实现原理实现我们手写的自定义代理类,实现简易的动态代理流程。

自定义InvocationHandler

package com.drj.bj.proxy.drjproxy;

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

/**
 * @author Drj
 * @version 1.0
 * @description: 自定义实现InvocationHandler
 * @date 2023/2/19 16:48
 */
public interface DrjInvocationHandler {
    public Object invoke(Object object, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException;
}

自定义类加载器

package com.drj.bj.proxy.drjproxy;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;

/**
 * @author Drj
 * @version 1.0
 * @description: 自定义类加载器
 * @date 2023/2/19 16:48
 */
public class DrjClassLoader extends ClassLoader {

    private File classPathFile;

    public DrjClassLoader() {
        String classPath = DrjClassLoader.class.getResource("").getPath();
        this.classPathFile = new File(classPath);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {

        String className = DrjClassLoader.class.getPackage().getName() + "." + name;
        if (classPathFile != null) {
            File classFile = new File(classPathFile, name.replaceAll("\\.", "/") + ".class");
            if (classFile.exists()) {
                FileInputStream in = null;
                ByteArrayOutputStream out = null;
                try {
                    in = new FileInputStream(classFile);
                    out = new ByteArrayOutputStream();
                    byte[] buff = new byte[1024];
                    int len;
                    while ((len = in.read(buff)) != -1) {
                        out.write(buff, 0, len);
                    }
                    return defineClass(className, out.toByteArray(), 0, out.size());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
}

自定义代理类

package com.drj.bj.proxy.drjproxy;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Drj
 * @version 1.0
 * @description: 手写代理类
 * @date 2023/2/19 17:24
 */
public class DrjProxy {
    public static final String ln = "\r\n";

    public static Object newProxyInstance(DrjClassLoader classLoader, Class<?>[] interfaces, DrjInvocationHandler drjInvocationHandler) throws IllegalArgumentException, IOException, NoSuchMethodException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //1、动态生成源代码.java文件
        String src = generateSrc(interfaces);
        //2、Java文件输出磁盘
        String filePath = DrjProxy.class.getResource("").getPath();
        File f = new File(filePath + "$Proxy0.java");
        FileWriter fw = new FileWriter(f);
        fw.write(src);
        fw.flush();
        fw.close();
        //3、把生成的.java文件编译成.class文件
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager manage = compiler.getStandardFileManager(null, null, null);
        Iterable iterable = manage.getJavaFileObjects(f);
        JavaCompiler.CompilationTask task = compiler.getTask(null, manage, null, null, null, iterable);
        task.call();
        manage.close();
        //4、编译生成的.class文件加载到JVM中来
        Class proxyClass = classLoader.findClass("$Proxy0");
        Constructor c = proxyClass.getConstructor(DrjInvocationHandler.class);
        f.delete();
        //5、返回字节码重组以后的新的代理对象
        return c.newInstance(drjInvocationHandler);
    }

    private static String generateSrc(Class<?>[] interfaces) {
        StringBuffer sb = new StringBuffer();
        sb.append("package com.drj.bj.proxy.drjproxy;" + ln);
        sb.append("import " + interfaces[0].getName() + ";" + ln);
        sb.append("import java.lang.reflect.*;" + ln);
        sb.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + ln);
        sb.append("DrjInvocationHandler h;" + ln);
        sb.append("public $Proxy0(DrjInvocationHandler h) { " + ln);
        sb.append("this.h = h;");
        sb.append("}" + ln);
        for (Method m : interfaces[0].getMethods()) {
            Class<?>[] params = m.getParameterTypes();

            StringBuffer paramNames = new StringBuffer();
            StringBuffer paramValues = new StringBuffer();
            StringBuffer paramClasses = new StringBuffer();

            for (int i = 0; i < params.length; i++) {
                Class clazz = params[i];
                String type = clazz.getName();
                String paramName = toLowerFirstCase(clazz.getSimpleName());
                paramNames.append(type + " " + paramName);
                paramValues.append(paramName);
                paramClasses.append(clazz.getName() + ".class");
                if (i > 0 && i < params.length - 1) {
                    paramNames.append(",");
                    paramClasses.append(",");
                    paramValues.append(",");
                }
            }

            sb.append("public " + m.getReturnType().getName() + " " + m.getName() + "(" + paramNames.toString() + ") {" + ln);
            sb.append("try{" + ln);
            sb.append("Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + m.getName() + "\",new Class[]{" + paramClasses.toString() + "});" + ln);
            sb.append((hasReturnValue(m.getReturnType()) ? "return " : "") + getCaseCode("this.h.invoke(this,m,new Object[]{" + paramValues + "})", m.getReturnType()) + ";" + ln);
            sb.append("}catch(Error _ex) { }");
            sb.append("catch(Throwable e){" + ln);
            sb.append("throw new UndeclaredThrowableException(e);" + ln);
            sb.append("}");
            sb.append(getReturnEmptyCode(m.getReturnType()));
            sb.append("}");
        }
        sb.append("}" + ln);
        return sb.toString();
    }

    private static Map<Class, Class> mappings = new HashMap<Class, Class>();

    static {
        mappings.put(int.class, Integer.class);
    }

    private static String getReturnEmptyCode(Class<?> returnClass) {
        if (mappings.containsKey(returnClass)) {
            return "return 0;";
        } else if (returnClass == void.class) {
            return "";
        } else {
            return "return null;";
        }
    }

    private static String getCaseCode(String code, Class<?> returnClass) {
        if (mappings.containsKey(returnClass)) {
            return "((" + mappings.get(returnClass).getName() + ")" + code + ")." + returnClass.getSimpleName() + "Value()";
        }
        return code;
    }

    private static boolean hasReturnValue(Class<?> clazz) {
        return clazz != void.class;
    }

    private static String toLowerFirstCase(String src) {
        char[] chars = src.toCharArray();
        chars[0] += 32;
        return String.valueOf(chars);
    }

}

测试自定义动态代理

接口类

package com.drj.bj.proxy.drjproxy;

/**
 * @author Drj
 * @version 1.0
 * @description: Person
 * @date 2023/2/19 16:07
 */
public interface DrjPerson {

    void play();
}

实现类

package com.drj.bj.proxy.drjproxy;

import com.drj.bj.proxy.Person;

/**
 * @author Drj
 * @version 1.0
 * @description: DrjPlayer
 * @date 2023/2/19 22:25
 */
public class DrjPlayer implements DrjPerson {

    @Override
    public void play() {
        System.out.println("我是自定義");
    }
}

基于自定义代理类的实现动态代理

package com.drj.bj.proxy.drjproxy;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author Drj
 * @version 1.0
 * @description: DrjJdkPlay
 * @date 2023/2/19 22:23
 */
public class DrjJdkPlay implements DrjInvocationHandler {

    private Object target;

    public Object getInstance(Object target) throws IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        this.target = target;
        return DrjProxy.newProxyInstance(new DrjClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object object, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
        before();
        Object invoke = method.invoke(this.target, args);
        after();
        return invoke;
    }

    private void before() {
        System.out.println("孩子长大了开始玩游戏……");
    }

    private void after() {
        System.out.println("成为职业玩家……");
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        DrjPerson instance = (DrjPerson) new DrjJdkPlay().getInstance(new DrjPlayer());
        instance.play();
    }
}

测试结果

孩子长大了开始玩游戏……
我是自定義
成为职业玩家……

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

自定义手写JDK动态代理 的相关文章

  • ubuntu更改网卡设置等出现输入default keyring密码的解决方法

    打开终端 xff0c 输入seahorse 如果提示没有seahorse命令的 span class hljs built in sudo span apt get install seahorse 然后在seahorse打开一个界面 之后
  • TV版应用包名 TV常用apk包名 (当贝市场下载)

    闲言 xff1a 其实有时候我觉得做一个前端的搬砖工特别的枯燥 xff0c 为了达到效果我们就不得不做很多枯燥的工作 xff0c 到头来 xff0c 只是为了显示一张图 xff0c 这种工作都不被看在眼里 xff0c 想想自己花了好多的时间
  • 沉浸式状态栏 (kotlin)

    object StatusBarKt 沉浸式状态栏 gt 6 0 fun fitSystemBar activity Activity if Build VERSION SDK INT lt Build VERSION CODES M re
  • Android studio的jdk路径查看

    很早之前android 开发的jdk和sdk都是要自己配置 xff0c xff0c 后来android studio下载安装之后就帮我们配置好了 我想用jdk的时候 xff0c 发现全局的环境变量没配 xff0c 那android stud
  • 人工智能(AI)入门

    人工智能的入门学习需要具备的知识结构 xff1a 一 编程语言选择 推荐python xff0c 原因有二 xff0c 其一 xff0c 语法简单易学 xff1b 其二 xff0c 有丰富的库支持 二 算法设计基础 人工智能的研究内容集中在
  • EditPlus之FTP连接linux服务器实现文件直接编辑

    1 点击File gt FTP gt FTP Settings 2 点击Add 输入linux的ip地址 用户名和密码 3 点击 Advanced Options 选择连接方式 sftp 端口 22 点击ok 4 点击 tools gt p
  • android App开启流程、广告图功能

    这里把加载后台配置的图片分成了两种 1 有网时 xff0c 用Glide去加载url地址的图片 xff0c 因为本身glide是有缓存 磁盘存储策略的 所以实际上只有第一次可能会有加载时间 xff0c 但是现在都5g 4g网加个图片基本上没
  • 跳转浏览器打开链接

    打开外部浏览器 public void openBrowser Context context String url final Intent intent 61 new Intent intent setAction Intent ACT
  • TV 纵向焦点居中ScrollView

    适用场景 xff1a 纵向 xff0c 超过1屏 xff0c 简单但样式不同的单选或多选按钮 例如一个TV设置页面里有几个已知的可选择项纵向排列 xff0c 需要获取焦点的view一直在屏幕中间 xff0c VerticalGridView
  • android:sharedUserId=“android.uid.system“ 系统级权限并重新系统签名 记录

    1 在自己的app的AndroidManifest xml内添加 android sharedUserId 61 34 android uid system 34 2 build build apk 生成未签名的apk文件 app debu
  • recycleview item textview 跑马灯效果

    android duplicateParentState 61 34 true 34 android ellipsize 61 34 marquee 34 android singleLine 61 34 true 34 android m
  • RGB 透明度 对应代码

    透明度具体对应百分比 xff1a 100 FF 95 F2 90 E6 85 D9 80 CC 75 BF 70 B3 65 A6 60 99 55 8C 50 80 45 73 40 66 35 59 30 4D 25 40 20 33
  • adb shell查看顶部的activity

    adb shell dumpsys activity top dumpsys activity activities 该指令用来查看堆栈也是极好的 xff0c 这样就很清晰的分析出当前页面的跳转和创建的情况 xff0c 方便查找问题的出错点
  • html布局(Layout)

    一列布局 1 页面内容区域有一个固定宽度 2 页面内容区域在浏览器窗口中自动适应居中 实现方式 xff1a box widht 自定义 xff1b margin 0 auto 固定宽度设置 1 以主流的分辨率来判断 二列布局 xff08 1
  • C# Button 按钮控件

    目录 1 工具箱添加按钮 2 代码添加按钮 2 1 方法一 xff1a 绑定事件 xff08 43 61 new EventHandler xff08 xff09 xff09 2 2 使用lamada表达式添加 1 工具箱添加按钮 xff0
  • 制作U盘启动盘变成两个盘符怎么办

    很多朋友在给电脑重装系统时都是通过U盘制作启动盘来操作的 xff0c 不知道大家有没有遇到过在制作启动盘时 xff0c 盘符变成两个的情况呢 xff1f 这里就和大家分享一下如何解决这个问题吧 更多重装系统教程尽在小白系统重装官网 系统 x
  • Maven连接MySQL数据库

    配置Maven 1 官网下载maven包 xff0c 解压到英文路径下 xff0c 找到conf文件夹中的settings xml文件 xff0c 打开后添加本地仓库的路径 xff1a 再添加阿里maven的镜像网址 xff1a 配置完成后
  • 任务栏图标消失怎么办?三种方法教你快速恢复

    最近许多小伙伴在更新了操作系统之后 xff0c 发现自己的电脑任务栏图标全部都消失了 xff0c 不知道怎么显示出来 xff0c 非常的影响使用 更多电脑教程在这里 方法一 xff1a 1 首先按下快捷键 ctrl 43 shift 43
  • Win10怎么搜索文件内容?Win10通过文件内容查找文件的方法

    Win10怎么搜索文件内容 xff1f 有些朋友电脑里的文件很多 xff0c 想要找到某个文件 xff0c 但是不记得文件名 xff0c 只知道里面是有关什么的内容 xff0c 想要通过搜索里面的文字内容来找到具体的文件 xff0c 今天介
  • vista系统重装下载安装教程

    平常我们使用的电脑操作系统基本都是windows系统 xff0c win7 10 11甚至是xp都是较为常用的操作系统 xff0c 而其它的心态比如说vista系统也是有用户在使用的 xff0c 那么该如何安装这个系统呢 xff1f 下面给

随机推荐

  • 电脑重装系统后找不到硬盘怎么办

    有网友的win10系统电脑出了系统故障进行了重装 xff0c 但是又发现了重装系统后找不到硬盘的新问题 xff0c 那么重装系统后找不到硬盘怎么办呢 工具 原料 xff1a 系统版本 xff1a win10专业版 品牌型号 xff1a 戴尔
  • Linux客户端挂载nas存储

    在Linux操作系统中 xff0c 可以使用NFS xff08 Network File System xff09 协议将NAS设备的共享文件系统挂载到本地计算机上 以下是使用NFS挂载NAS设备的步骤 xff1a 确认NAS设备已经正确配
  • 合理使用CSDN-markdown编辑器进行转载

    转载自 xff1a https blog csdn net My daily life article details 108773671 前言 作为DSCN博客用户小萌新 xff0c 有可能自己写的博客还不够好 xff0c 或者当看到别人
  • python中break和continue的区别

    python中break和continue的区别 break 应用在循环中 xff0c 结束当前循环 continue 应用在循环中 xff0c 结束当前正在执行的循环 xff0c 继续下一次循环 实例 xff1a 统计100 200之间的
  • Ubantu基础指令大集合

    Ubantu基础指令大集合 1 打开ubantu终端 Ctrl 43 alt 43 T 2 定位到需要操作的文件夹cd cd home drl document 3 查询同级目录下其他文件夹tab 按下tab 4 查看该文件夹下有什么文件l
  • Shell脚本代码编写规则

    Shell脚本代码编写规则 Shell解释器 解释器 xff08 例如 xff1a bin bash xff09 2 Shell的变量类型 环境变量 Shell环境下已经存在的一些系统变量 xff0c eg PWD UID PATH 自定义
  • HTML基本表格的使用

    基本表格的使用 lt DOCTYPE html gt lt html gt lt head gt lt meta charset 61 34 utf 8 34 gt lt title gt 基本表格 lt title gt lt head
  • 华为私有云平台FusionCompute搭建

    一 FusionCompute架构 架构CNA作为虚拟化操作系统 xff0c VRM作为虚拟化管理平台 正常主机都安装CNA xff0c 单独建立VRM集群作为管理集群 xff0c 我测试环境就一台主机 xff0c 所以CNA和VRM装在同
  • HTML中的表格合并

    HTML中的表格合并 lt DOCTYPE html gt lt html gt lt head gt lt meta charset 61 34 utf 8 34 gt lt title gt lt title gt lt head gt
  • vba 正则表达式

    群友分享的 xff0c 内容解释非常清楚 Sub RegTest Dim oRegExp As Object 39 定义正则表达式对象 Dim oMatches As Object 39 定义匹配字符串集合对象 Dim str As Str
  • 一个可以直接使用的用于python日志记录的类

    一个用于Python3程序的日志记录类 xff0c 使用的时候 xff0c 将该类import进去后 xff0c 按照这里面的最后两行的测试程序使用即可 程序贴在这里 xff0c 省的以后造轮子 Github xff1a https git
  • python 安装 第三方库报错 -— 需要Visual C++ 14.0 compiler 及以上

    python 安装 第三方库报错 xff1a error Microsoft Visual C 43 43 14 0 or greater is required Get it with 34 Microsoft C 43 43 Build
  • 时间序列模型 (一):模型概述

    时间序列的其它博文系列 xff1a 时间序列模型 xff08 一 xff09 xff1a 模型概述 时间序列模型 xff08 二 xff09 xff1a 移动平均法 时间序列模型 xff08 三 xff09 xff1a 指数平滑法 时间序列
  • ubantu18开启audit审计日志

    1 检查系统是否安装audit服务 service auditd status 2 安装命令 sudo apt get install auditd 审计规则 auditctl w etc passwd p rwxa xff08 注意 xf
  • CentOS8 使用yum 安装 jdk8

    原文地址 1 安装方法 CentOS8上使用 yum 直接安装 xff0c 环境变量自动配置好 2 查看是否已安装 看到下面结果 xff0c 说明已经安装配置 jdk 1 2 3 4 root 64 localhost java versi
  • npm 更新不了,一直提示not support Node.js v12.18.4

    使用npm命令一直提示 xff1a npm WARN npm npm does not support Node js v12 18 4 根据网上提供的方法是全局更新npm npm i g npm 运行后仍然一直提示 npm WARN np
  • 特别实用而且功能强大的attributedText属性

    span class hljs preprocessor import span class hljs title 34 ViewController h 34 span span span class hljs preprocessor
  • 基本计算器算法实现

    基本计算器 没有括号基本计算 题目 给你一个字符串表达式 s xff0c 请你实现一个基本计算器来计算并返回它的值 整数除法仅保留整数部分 你可以假设给定的表达式总是有效的 所有中间结果将在 231 231 1 的范围内 注意 xff1a
  • 在windows和ubuntu下安装Syncthing

    Syncthing 一个可以用在不同设备之间 xff0c 同步文件的工具 window下安装 有客户端版本的 xff0c 由社区维护 xff0c 我下下来试了下 xff0c 没有跟到最新版本 xff0c 看其他文章好像有 bug xff0c
  • 自定义手写JDK动态代理

    前言 根据Java Porxy 实现原理实现我们手写的自定义代理类 xff0c 实现简易的动态代理流程 自定义InvocationHandler span class token keyword package span com span