jdk动态代理介绍及invoke方法自动运行的原因

13 篇文章 1 订阅
订阅专栏

什么是代理?
在生活中,当我们有访问Google的需求的时候,就需要通过代理服务器进行访问。而代码中的"代理"也与之相似,当我们访问某个对象的时候,我们也可以通过"代理"来对其进行访问。

代理模式

学习java的动态代理以前,要明白java的代理模式,下面是从知乎专栏找到的一张图。
在这里插入图片描述

java中的静态代理

以买房子为例我们可以去找中介,那么这里的中介就是代理者。
写个domo更方便理解一下:
先定义一个IUser接口:

public interface IUser {
    void show();
}

实现类:

public class UserImpl implements IUser{
    public UserImpl() {

    }
    @Override
    public void show() {
        System.out.println("高楼,中楼,别墅");
    }
}

代理类

import java.text.SimpleDateFormat;
import java.util.Date;

public class StaProxy implements IUser{

    IUser user;

    public StaProxy(IUser user){
        this.user=user;
    }

    @Override
    public void show() {
        this.show();


        Date date = new Date();
        SimpleDateFormat dateFormat= new SimpleDateFormat("yyyy-MM-dd :hh:mm:ss");
        System.out.println("您在"+dateFormat.format(date)+"观看了房源,是否想进行购买?");

    }
}

main

public class ProxyTest {
    public static void main(String[] args) {
            IUser user = new UserImpl();
            IUser sp = new StaProxy(user);
            sp.show();

    }
}

运行结果:
在这里插入图片描述

这样我们就通过我们写的静态代理来在调用show方法展示的同时,还记录了时间,并且还进行了进一步的询问,但是使用静态代理有一个大大的弊端,就是当我们在接口中想增加新的方法时不仅我们的实现类里面要有大的改动,我还要改变我们的代理类,这是极不方便的,并且我们的重复代码也是要写很多。为了解决这种情况,就要学习Java的动态代理

java中的动态代理

先写一个demo在进行分析
Iuser接口

public interface IUser {
    void show();
}

实现类

public class UserImpl implements IUser{
    public UserImpl() {

    }
    @Override
    public void show() {
        System.out.println("高楼,中楼,别墅");
    }
}

处理器

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

public class UserInvocationHanlder implements InvocationHandler {

    IUser user;
    public UserInvocationHanlder(IUser user) {
        this.user=user;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        method.invoke(user,args);
        return null;
    }
}

main

import java.lang.reflect.Proxy;

public class ProxyTest {
    public static void main(String[] args) {

        IUser user = new UserImpl();

        UserInvocationHandler han = new UserInvocationHandler(user);

        IUser iUser = (IUser)  Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(),han);
        iUser.show();

    }
}

运行结果

在这里插入图片描述
其实这里就是在我们调用我们的某个方法时候,会进行动态获取我们的方法名,在通过我们传入的实现类对象,来进行动态调用我们对象的方法,我们上面写的处理器其实就是发挥着"动态代理"的作用。(提到动态大家估计一定会猜到用到了反射,所以明白一些底层原理还是很重要的)

动态代理在反序列化攻击中的作用

为什么要讲动态代理这个机制呢?

  1. 动态代理类接收的参数都是Object
  2. 当我们创建的动态代理对象调用任意一个方法时,都会调用我们自定义的继承于InvocationHandler的类的invoke方法。这就为我们挖掘gadget时会多出一点路来。

jdk动态代理为何会自动运行invoke

我们首先来看一下,我们的 iUser 是一个什么样的对象:

在这里插入图片描述
可以看到我们的生成的代理对象iUser是属于com.sun.proxy.$Proxy0这个类,我们在代码中加上System.getProperties().put(“sun.misc.ProxyGenerator.saveGeneratedFiles”, “true”);这样一段代码,执行后,就会把我们的$Proxy0.class 生成出来:

在这里插入图片描述
可以直接看到反编译后的代码:

在这里插入图片描述
完整代码:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.sun.proxy;

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

public final class $Proxy0 extends Proxy implements IUser {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void show() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("IUser").getMethod("show");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

我们大致知道 Proxy.newProxyInstance 生成的是个"什么东西"以后,我们去看下这个newProxyInstance方法来了解它是如何生成的。

newProxyInstance方法代码:

 public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

这个函数他有三个参数,第一个参数是类加载器,第二个参数是一个接口数组,第三个参数是InvocationHandler接口的子类,我们来看下这个newProxyInstance函数代码的第一个关键部分:
在这里插入图片描述

在上图的方法getProxyClass0 中 会创建出一个类Proxy0,这个就是我们前面的那个Proxy0.class对应的类。在我们调用getProxyClass0 时,它的第二个参数是我们传入的接口,他会将我们传入的借口进行遍历,并且将这些接口中定义的方法进行实现。这里实现的方法的代码可以在上文说过的那个class文件上看到:
在这里插入图片描述

我们再接着来看下这个newProxyInstance函数代码的第二个关键部分:

在这里插入图片描述
这里是来获取proxy0这个类的构造器,参数是InvocationHandler。接着他又将h变量赋值给了别的变量,这个h变量就是我们传进去的第三个参数,即一个InvocationHandler接口的子类。

在这里插入图片描述
newProxyInstance函数代码的第三个关键部分,也是最后的地方,通过反射的方式创建proxy0对象并返回,至此,newProxyInstance方法执行完毕
在这里插入图片描述
可以看一下Proxy0的构造方法的代码,实际上是调用了他父类就是proxy的构造方法:
在这里插入图片描述

了解完大概的过程以后,我们在看之前的问题invoke方法是怎么自动运行的?

当我们通过代理对象调用show方法时:
在这里插入图片描述

因为iUser是Proxy0的实例对象,所以调用的show方法就是Proxy0类中的show方法。此时就相当于是proxy0.show。我们去看一眼对应的代码:
在这里插入图片描述
此时便会进到show方法,去执行 super.h.invoke ,这里的super是父类即proxy类,这里的h就是我们父类中的变量h,即是我们传进去的那个InvocationHandler的子类。所以super.h.invoke实际上就是在调用我们自定义的InvocationHandler的子类 UserInvocationHanlder的invoke方法:

在这里插入图片描述

以上就是invoke方法会自动运行的原因。

动态代理invoke 方法详解、动态代理流程梳理
weixin_57667101的博客
11-14 1168
动态代理invoke 方法详解、动态代理流程梳理
paddy.w InvocationHandler中invoke()方法的调用问题
baidu_20977425的专栏
09-18 410
以下的内容部分参考了网络上的内容,在此对原作者表示感谢! Java动态代理的实现,关键就是这两个东西:Proxy、InvocationHandler,下面从InvocationHandler接口中的invoke方法入手,简单说明一下Java如何实现动态代理的。 首先,invoke方法的完整形式如下: Java代码 public Object inv
JavaSec:Java安全学习的宝库
最新发布
gitblog_00554的博客
08-12 383
JavaSec:Java安全学习的宝库 JavaSeca rep for documenting my study, may be from 0 to 0.1项目地址:https://gitcode.com/gh_mirrors/ja/JavaSec 项目介绍 JavaSec 是一个专注于Java安全学习的开源项目,由@Y4tacker创建于2021年10月18日。这个项目不仅仅是一个教学仓库,...
为什么总去调用invoke方法
m0_37609060的博客
07-21 453
动态代理为什么每一次都去调用invoke方法,因为jdk动态代理在字节码层面上生成了接口的类 // // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package com.sun.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; i
JDK 动态生成的代理对象在调用方法时,为什么总掉我们实现的InvocationHandler接口里面的invoke方法
weixin_45283443的博客
07-31 732
JDK 动态生成的代理类 查看 在生成代理类前加入System.getProperties().put(“sun.misc.ProxyGenerator.saveGeneratedFiles”,“true”); 设置,即在 Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{SpiTest.class}, new Invo...
动态代理 InvocationHandler中的invoke()方法是在哪被调用的?
qq_41748678的博客
07-26 397
在执行这个方法之前,Java虚拟机调用与代理对象关联的 `InvocationHandler` 的 `invoke()` 方法,并将相应的参数传递给它。在 `invoke()` 方法中,我们可以根据需要进行一些操作,例如记录日志、执行前置或后置逻辑,然后再通过 `Method.invoke()` 方法调用原始对象的方法并返回相应的结果。因此,`InvocationHandler` 的 `invoke()` 方法代理对象的方法被调用时被Java虚拟机触发,将执行我们所定义的自定义逻辑。
浅谈JDK动态代理与CGLIB代理去区别
03-01
在性能方面,JDK动态代理由于不涉及字节码生成,所以在运行时的性能通常优于CGLIB。然而,如果目标类的方法很多,CGLIB可能更高效,因为它只需创建一次子类,而JDK动态代理每次调用都需要通过InvocationHandler。...
你必须JDK 动态代理和 CGLIB 动态代理
12-21
动态代理类在程序运行时由Java虚拟机自动生成,不需要预先编写代理类的源代码。动态代理主要依赖于`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口。 ```java // 实现InvocationHandler ...
JDK动态代理和CGLIB代理
01-10
Java动态代理Java编程中一个重要的特性,它允许我们在运行时创建对象的代理,从而实现对原对象的一些额外操作或扩展功能。JDK动态代理和CGLIB代理是两种常用的实现方式。 首先,我们来看看JDK动态代理JDK动态...
spring-demo16-JDK动态代理.zip
08-17
Java开发中,JDK动态代理是一个非常重要的概念,它允许我们在运行时创建对已有接口的代理实现。Spring框架在很多场景下也利用了这一特性,例如AOP(面向切面编程)就是其中之一。"spring-demo16-JDK动态代理.zip...
关于jdk动态代理的源码剖析
06-18
动态代理类是由JDK自动生成的类,它的结构主要包括以下几个方面: 1. **代理类继承自`Proxy`类**:每一个动态代理类都是`Proxy`类的子类,这意味着它们继承了`Proxy`类中的所有属性和方法。 2. **代理类实现了目标...
InvocationHandler实现类中的invoke方法为什么自动执行
m0_57713282的博客
12-08 1336
一:首先需要明确的是动态代理中,InvocationHandler实现类并不是代理类,只是代理类与被代理类的一个中间类,这也是动态代理能够解耦的原因 二:动态代理中的代理类是通过Proxy.newInstance方法,即反射生成代理类实例的,该代理类中有一个与被代理方法同名的成员方法,而该成员方法的实现实际就是调用了InvocationHandler实现类的invoke方法,即通过代理类实例调用该成员方法实际调用的是InvocationHandler实现类的invoke方法。而InvocationHa
JDK动态代理,InvocationHandler接口的invoke方法自动执行分析
kkk990101的博客
05-09 786
当执行subject.request()方法时,就调用了$Proxy0类中的request()方法,进而调用父类Proxy中的h的invoke()方法,即InvocationHandler.invoke()。大致能猜到是通过Proxy类的静态方法newProxyInstance时,它的底层调用了InvocationHandler接口实现类PigHandler中重写的invoke方法。这个$Proxy0类是Proxy类的子类
Java动态代理invoke方法自动执行的原因
weixin_44245705的博客
06-18 1197
动态代理中,一般的是先调用Proxy.newProxyInstance()生成代理对象,然后通过调用代理对象的对应方法来实现增强,这里假设代理了被代理对象的test()方法。其中增强的逻辑写在处理器中(InvocationHandler处理器常通过匿名内部类创建)。当调用代理对象的test方法时,处理器中的invoke方法自动执行,这一点较难理解。以下尝试从源码的角度对动态代理的机制进行简要分析。 $Proxy0类中的主体(代理对象是该类的实例) 通过匿名内部类创建处理器(InvocationHand
30.AOP源码之JDK代理对象invoke方法调用
qq_30635523的博客
06-14 306
highlight: arduino-light 在jdk动态代理invoke方法中的三个参数分别是什么呢? 以addProduct()方法为例,此时执行这行代码: java super.h.invoke(this, m3, new Object[]{var1}) 第一个参数this没啥好说的,就是当前代理对象自己,也就是\$Proxy13类的对象, 而第二个参数m3是在一个s...
从Mybatis源码理解jdk动态代理默认调用invoke方法
yanbin
04-10 248
一、背景最近在工作之余,把mybatis的源码看了下,决定自己手写个简单版的。实现核心的功能即可。写完之后,执行了一下,正巧在mybatis对Mapper接口的动态代理这个核心代码这边发现一个问题。正好再回头看下jdk动态代理,才发现问题所在。 二、问题当我用SqlSession.getMapper() 方法来获取Mapper的代理类的时候,发现这个代理对象所展示的toString(...
JDK动态代理
初中生的博客
02-06 365
1、背景    Spring AOP使用动态代理技术在运行期织入增强的代码,Spring AOP 的底层使用了两种代理模式一种是JDK动态代理,另一种是基于CGLIB的动态代理。之所以需要两种代理机制,很大程度上是因为JDK本身只提供接口的代理,而不支持类的代理。    2、JDKProxy的代码 package com.itheima.spring.jdkproxy;pub
jdk动态代理invoke方法自动运行原因
qq_39056197的博客
10-17 5089
invoke 方法介绍 想要知道 invoke方法为什么自动调用我们先要来了解一下这个方法 public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) 首先 该方法来自于接口InvocationHandler ,该接口中仅有一个invoke方法 ,该...
java动态代理中的invoke方法
wzw的博客
07-08 3664
前言 记录一篇好的文章 https://blog.csdn.net/zcc_0015/article/details/22695647 同时推荐狂神说的视频,对于动态代理讲解的很详细 https://www.bilibili.com/video/BV1WE411d7Dv?p=19 一、动态代理与静态代理的区别 (1)Proxy类的代码被固定下来,不因为业务的逐渐庞大而庞大; (2)可以实现AOP编程,这是静态代理无法实现的; (3)解耦,如果用在web业务下,可以实现数据层和业务层的分离。 (4)动态代理
写文章

热门文章

  • Thinkphp3全漏洞分析 6543
  • javaSec-Servlet的线程安全问题 3692
  • Weblogic 未认证远程命令执行(CVE-2020-14882、CVE-2020-14883) 3640
  • Weblogic 常规渗透测试之利用文件读取漏洞getshell 2738
  • CTFSHOW—反序列化 2631

分类专栏

  • javasec 13篇
  • 代码审计 13篇
  • Weblogic漏洞复现 5篇
  • CTFSHOW刷题记录 11篇
  • tomcat 2篇
  • XCTF刷题记录 1篇
  • 逆向学习 1篇
  • ctf比赛wp 3篇
  • 强网杯2021wp 1篇
  • PHPwebshell混淆与深度利用 1篇
  • BUUCTF刷题记录 1篇
  • apache所有漏洞复现 5篇
  • nginx 6篇
  • CTFHUB刷题记录

最新评论

  • jdk动态代理介绍及invoke方法自动运行的原因

    CV工程师丁Sir: 我们调用的show()方法实际上是InvocationHandler里面的show()方法

  • CTFSHOW-SSTI

    oywlfirst: 师傅能不能分享一下你ssti的字典啊

  • 嘟嘟牛app算法hook

    None安全团队: app能给个链接吗

  • MS14-068 漏洞分析—不安全的PAC

    get嘤嘤嘤: 文章内容丰富,条理清晰,值得一波关注,如沐春风,配图也很有趣,希望作者也指点我一番!🍒🍒🍒🍒∠(`ω´*)敬礼✧(≖ ◡ ≖✿)

  • Nginx 配置错误导致漏洞——add_header被覆盖

    nobms: 好的谢谢博主

最新文章

  • 一些真实的app渗透与算法hook
  • 从xxe到rce-记一道ctf中的java题
  • fastjson反序列化链分析与bypass
2023年8篇
2022年17篇
2021年59篇
2020年11篇

目录

目录

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值

玻璃钢生产厂家浙江通用玻璃钢雕塑摆件三明玻璃钢海豚雕塑山东周年庆典商场美陈价钱嘉峪关户外玻璃钢雕塑设计北京景区玻璃钢雕塑厂家抽象玻璃钢仿铜雕塑生产厂家方形插花玻璃钢花盆玻璃钢雕塑维修方案中原区玻璃钢广场雕塑萍乡玻璃钢雕塑销售厂家玻璃钢人物雕塑厂家推荐深圳艺术商场美陈销售公司新乡玻璃钢雕塑厂家哪家好保定玻璃钢卡通雕塑厂陇南玻璃钢雕塑销售个性化玻璃钢雕塑定制湖南卡通玻璃钢雕塑价格园艺园林玻璃钢雕塑西安玻璃钢抽象雕塑玻璃钢雕塑女尸松原玻璃钢花盆生产厂家崇仁玻璃钢雕塑厂家甘肃卡通玻璃钢雕塑公司玻璃钢人物雕塑特色徐州地区做玻璃钢雕塑揭阳景观玻璃钢雕塑江西玻璃钢雕塑哪里好丽江市玻璃钢雕塑设计价格表咸宁市玻璃钢雕塑厂盐城设计玻璃钢雕塑香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化