返回顶部
首页 > 资讯 > 后端开发 > JAVA >Java中的动态代理
  • 151
分享到

Java中的动态代理

javaPoweredby金山文档 2023-09-06 08:09:47 151人浏览 薄情痞子
摘要

一、Java中的两种动态代理方式 Java中常用的有两种动态代理方式,分别为:jdk动态代理和Cglib动态代理。 JDK动态代理是通过实现接口的方式完成动态代理。 Cglib动态代理是通过继承目标类或实现接口的方式完成动态代理。

一、Java中的两种动态代理方式

Java中常用的有两种动态代理方式,分别为:jdk动态代理和Cglib动态代理。

JDK动态代理是通过实现接口的方式完成动态代理。

Cglib动态代理是通过继承目标类或实现接口的方式完成动态代理。

二、JDK动态代理

JDK动态代理中最核心的就是Proxy类和InvocationHandler接口。

Proxy类

通过调用这个类中的静态方法newProxyInstance(),可以返回代理对象。

newProxyInstance()方法需要三个参数,分别是:ClassLoader类加载、目标对象实现的所有接口、InvocationHandler实现类。

InvocationHandler接口

这个接口中有一个invoke方法,代理对象通过调用这个方法对目标方法进行增强。

三、案例

需求

需求:创建计算器类,进行加减乘除运算。同时需要在进行加减乘除之前打印参数信息,在加减乘除之后打印计算结果。

创建类实现功能

创建Calculator计算器接口,提供加减乘除方法,创建实现类,并完成打印参数与计算结果的功能。

接口:

package com.demo.dynamic_proxy.jdk;public interface Calculator {    int add(int a, int b);  // 加法    int sub(int a, int b);  // 减法    int mul(int a, int b);  // 乘法    int div(int a, int b);  // 除法}

实现类:

public class CalculatorImpl implements Calculator {    @Override    public int add(int a, int b) {        System.out.println("执行add方法,参数信息:" + a + "," + b);        int result = a + b;        System.out.println("add方法执行完毕,计算结果:" + result);        return result;    }    @Override    public int sub(int a, int b) {        System.out.println("执sub方法,参数信息:" + a + "," + b);        int result = a + b;        System.out.println("sub方法执行完毕,计算结果:" + result);        return result;    }    @Override    public int mul(int a, int b) {        System.out.println("执行mul方法,参数信息:" + a + "," + b);        int result = a + b;        System.out.println("mul方法执行完毕,计算结果:" + result);        return result;    }    @Override    public int div(int a, int b) {        System.out.println("执行div方法,参数信息:" + a + "," + b);        int result = a + b;        System.out.println("div方法执行完毕,计算结果:" + result);        return result;    }}

分析存在的问题

如果将打印参数信息和打印计算结果的代码都写到实现类中,会出现以下问题:

1)代码比较分散,过于冗余 ,可以将打印参数信息和结果的代码提取到工具类中。

2)代码过于混乱,非核心业务代码(输出语句)与核心业务代码(加减乘除操作)混合到了一起,不好维护。

可以通过动态代理的方式,对功能进行增强,不需要在业务代码(加减乘除的运算)中添加非核心业务代码(打印参数和结果的代码)

改进代码

将代码提取到工具类中

package com.demo.dynamic_proxy.jdk.util;import java.util.Arrays;public class Logging {        public static void beforeMethod(String className, String methodName, Object[] args){        System.out.println("执行" + className + "类中的" + methodName + "方法,参数:" + Arrays.toString(args));    }        public static void afterMethod(String className, String methodName, Object result){        System.out.println(className + "类中的" + methodName + "方法执行完毕,结果:" + result);    }}

使用动态代理的方式对功能进行增强

增强的功能:方法执行之前打印参数、方法执行之后打印结果。

实现步骤,分为四步:

1)创建类【用来生成代理对象】

2)在类中提供目标对象属性 ,需要被增强的对象。

3)在类中提供有参构造器为目标对象属性赋值 。

4)提供获取代理对象的方法。

package com.demo.dynamic_proxy.jdk;import com.demo.dynamic_proxy.jdk.util.Logging;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class MyProxy {    // 目标对象,需要增强的对象    private Object target;    // 有参构造器为目标对象进行赋值    public MyProxy(Object target) {        this.target = target;    }    // 获取代理对象的方法    public Object getProxyObject(){        // 代理对象        Object proxyObject = null;        // 获取类加载器        ClassLoader classLoader = target.getClass().getClassLoader();        // 获取目标对象实现的所有接口        Class[] interfaces = target.getClass().getInterfaces();        // 调用Proxy.newProxyInstance()方法,创建代理对象        proxyObject = Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {                        @Override            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                // 目标对象类名                String targetClassName = target.getClass().getName();                // 要执行的方法名                String targetMethodName = method.getName();                // 在方法调用之前,打印方法参数                Logging.beforeMethod(targetClassName, targetMethodName, args);                // 调用目标对象的方法                Object result = method.invoke(target, args);                // 调用方法之后,输出执行结果                Logging.afterMethod(targetClassName, targetMethodName, result);                // 将执行结果返回                return result;            }        });        // 将代理对象返回        return proxyObject;    }}

测试代码

@Testpublic void test(){    // 创建目标对象,也就是需要被增强的对象    CalculatorImpl calculator = new CalculatorImpl();    // 创建MyProxy并获取代理对象    MyProxy myProxy = new MyProxy(calculator);    Calculator proxyObject = (Calculator) myProxy.getProxyObject();    // 调用方法    proxyObject.add(1, 2);}

执行结果:

执行com.demo.dynamic_proxy.jdk.impl.CalculatorImpl类中的add方法,参数:[1, 2]正在执行add方法......com.demo.dynamic_proxy.jdk.impl.CalculatorImpl类中的add方法执行完毕,结果:3

我们通过动态代理的方式完成了参数和执行结果的打印功能,以后需要调整打印信息时,只需要修改一处即可。

四、底层原理分析

JDK动态代理是如何生成代理对象的呢?底层真的没有创建类吗?

底层其实是有创建类的,Java中必须有类才能够使用这个类的实例,JDK动态代理运行时,底层创建代理类实现目标对象的接口,并生成代理类的字节码,通过类加载器将字节码进行加载,最后再生成代理类对象实例。

查看Proxy类的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);        }                // 通过这个方法来生成代理类        Class cl = getProxyClass0(loader, intfs);                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() {                    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);        }    }

其中,通过getProxyClass0方法来获取代理类

Class cl = getProxyClass0(loader, intfs);

getProxyClass0方法中有一段核心的代码:

byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces);

这段代码就是生成代理类的字节码信息的。

我们试着调用这个方法,并获取到class字节码:

@Testpublic void test01(){    // 要生成的类的名称    String className = "myClass";    // 指定class类名以及代理类要实现的接口    byte[] bytes = ProxyGenerator.generateProxyClass(className, new Class[]{Calculator.class});    FileOutputStream fos = null;    try {        // 将生成的字节信息输出到 myClass.class        fos = new FileOutputStream(new File("D:\\" + className + ".class"));        fos.write(bytes);    }catch (Exception e){        System.out.println(e.getMessage());    }finally {        if(fos != null){            try {                fos.close();            } catch (IOException e) {                e.printStackTrace();            }        }    }}

使用反编译工具打开class文件,这里使用的是idea

字节码中的add方法:

完整代码:

//// Source code recreated from a .class file by IntelliJ IDEA// (powered by FernFlower decompiler)//import com.demo.dynamic_proxy.jdk.Calculator;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.lang.reflect.UndeclaredThrowableException;public final class myClass extends Proxy implements Calculator {    private static Method m1;    private static Method m2;    private static Method m4;    private static Method m3;    private static Method m6;    private static Method m5;    private static Method m0;    public myClass(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 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 mul(int var1, int var2) throws  {        try {            return (Integer)super.h.invoke(this, m4, new Object[]{var1, var2});        } catch (RuntimeException | Error var4) {            throw var4;        } catch (Throwable var5) {            throw new UndeclaredThrowableException(var5);        }    }    public final int add(int var1, int var2) throws  {        try {            return (Integer)super.h.invoke(this, m3, new Object[]{var1, var2});        } catch (RuntimeException | Error var4) {            throw var4;        } catch (Throwable var5) {            throw new UndeclaredThrowableException(var5);        }    }    public final int sub(int var1, int var2) throws  {        try {            return (Integer)super.h.invoke(this, m6, new Object[]{var1, var2});        } catch (RuntimeException | Error var4) {            throw var4;        } catch (Throwable var5) {            throw new UndeclaredThrowableException(var5);        }    }    public final int div(int var1, int var2) throws  {        try {            return (Integer)super.h.invoke(this, m5, new Object[]{var1, var2});        } catch (RuntimeException | Error var4) {            throw var4;        } catch (Throwable var5) {            throw new UndeclaredThrowableException(var5);        }    }    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"));            m2 = Class.forName("java.lang.Object").getMethod("toString");            m4 = Class.forName("com.demo.dynamic_proxy.jdk.Calculator").getMethod("mul", Integer.TYPE, Integer.TYPE);            m3 = Class.forName("com.demo.dynamic_proxy.jdk.Calculator").getMethod("add", Integer.TYPE, Integer.TYPE);            m6 = Class.forName("com.demo.dynamic_proxy.jdk.Calculator").getMethod("sub", Integer.TYPE, Integer.TYPE);            m5 = Class.forName("com.demo.dynamic_proxy.jdk.Calculator").getMethod("div", Integer.TYPE, Integer.TYPE);            m0 = Class.forName("java.lang.Object").getMethod("hashCode");        } catch (NoSuchMethodException var2) {            throw new NoSuchMethodError(var2.getMessage());        } catch (ClassNotFoundException var3) {            throw new NoClassDefFoundError(var3.getMessage());        }    }}

五、总结

  1. JDK动态代理是通过实现接口的方式完成对目标对象功能的增强。

  1. JDK动态代理底层创建代理类,实现目标对象所实现的接口,并生成代理类的字节码信息,通过类加载器进行加载,最后创建代理类对象,通过代理对象调用InvocationHandler接口实现类的invoke方法完成功能的增强。

  1. 通过调用Proxy类的newProxyInstance方法创建代理对象,代理对象调用InvocationHandler接口中的invoke实现对目标对象的增强功能。

来源地址:https://blog.csdn.net/qingfengmax/article/details/129172456

--结束END--

本文标题: Java中的动态代理

本文链接: https://lsjlt.com/news/396677.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Java中的动态代理
    一、Java中的两种动态代理方式 Java中常用的有两种动态代理方式,分别为:JDK动态代理和Cglib动态代理。 JDK动态代理是通过实现接口的方式完成动态代理。 Cglib动态代理是通过继承目标类或实现接口的方式完成动态代理。 ...
    99+
    2023-09-06
    java Powered by 金山文档
  • 浅析Java中的动态代理
    目录代理常见功能代理模式的组成代理模式分类动态代理实现的技术JDK 代理的实现步骤CGLIB 代理实现步骤代理常见功能 日志代理 数据库访问的事务代理 代理模式的组成 抽象主题:通过...
    99+
    2024-04-02
  • 详解java 中的动态代理
    这期内容当中小编将会给大家带来有关详解java 中的动态代理,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Java动态代理相关先来看静态代理模式代码:package test; public inter...
    99+
    2023-05-31
    java 动态代理 ava
  • java动态代理
    生成步骤 1. Proxy.newProxyInstance2. Constructor cons = getProxyConstructor(caller, loader, interfaces);3. (ld, clv) -> new ...
    99+
    2023-08-30
    java python 开发语言
  • Java动态代理的原理
    Java动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类。(推荐:java视频教程)代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过程中,开发人员还...
    99+
    2015-03-30
    Java
  • Java中动态代理和静态代理的示例分析
    这篇文章主要介绍了Java中动态代理和静态代理的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。0、代理模式为什么要学习代理模式?这是SpringAOP的底层【Spri...
    99+
    2023-06-29
  • Java的动态代理和静态代理详解
    目录0、代理模式1、静态代理2、 加深理解3、动态代理动态代理的例子总结0、代理模式 为什么要学习代理模式?这是SpringAOP的底层【SpringAOP和SpringMVC】 代...
    99+
    2024-04-02
  • java静态代理与动态代理的概念
    本篇内容介绍了“java静态代理与动态代理的概念”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!    ...
    99+
    2023-06-02
  • Java中的动态代理是什么
    本篇内容介绍了“Java中的动态代理是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!十分钟理解 Java 中的动态代理一、概述 什么是代...
    99+
    2023-06-02
  • Java 动态代理你真的懂了吗(动态和代理)
    好几天不写文章,今天来写一篇,从之前的计划表上看到还有关于java的动态代理没写,这个技术平常用的少,也不是特别好理解,今天补上这篇,希望能讲明白,不至于像我一样迷茫好久,开始吧 动...
    99+
    2024-04-02
  • Java——JDK动态代理
    1.动态代理 1.1什么是动态代理? 动态代理(理解) 基于反射机制 举个例子,生活中一般在打官司的时候都会请代理律师,为什么要请律师呢?是因为开庭的时候大部人对于打官司没有经验,只会说出自己案件的陈述,并不会根据法律等争取自己权益...
    99+
    2023-08-31
    java 开发语言
  • JAVA中静态代理与动态代理的区别有哪些
    这期内容当中小编将会给大家带来有关JAVA中静态代理与动态代理的区别有哪些,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。代理模式是java中最常用的设计模式之一,尤其是在spring框架中广泛应用。对于j...
    99+
    2023-05-31
    java 静态代理 动态代理
  • java代理模式(静态代理、动态代理、cglib代理)
    目录代理模式静态代理代码接口被代理对象代理对象测试动态代理代码:接口目标对象代理对象测试cglib代理代码:目标对象代理对象测试应用总结代理模式 代理模式(Proxy Pattern...
    99+
    2024-04-02
  • Java 静态代理与动态代理解析
    目录一、代码实践静态代理动态代理二、常见的动态代理场景Retrofit中的动态代理使用动态代理实现 onClick注入三、源码探索 Jdk 中的动态代理生成代理类四、总结静态代理: ...
    99+
    2024-04-02
  • JAVA的动态代理详解
    文章目录 前言一、动态是什么?二、使用步骤1.导入相应的包2.定义接口3.定义接口实现类4.实现InvocationHandler接口5.实现代理 三、整体实例四、输出结果总结 前言...
    99+
    2023-08-31
    java 开发语言
  • JAVA代理,静态,动态详解
    目录代理静态代理动态代理JDK动态代理CGLib动态代理总结代理 为其他对象提供一种代理以控制这个对象的访问,在某些情况下一个对象不能直接访问那个对象时,代理就起到了客户端和被代理对...
    99+
    2024-04-02
  • Java静态代理和动态代理的深入讲解
    代理模式 代理模式(Proxy):为其他对象提供一个代理以控制对这个对象的访问。 主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对...
    99+
    2024-04-02
  • 深入理解Java动态代理与静态代理
    目录前言一、静态代理静态代理的使用与装饰者模式的区别二、动态代理JDK 动态代理CGlib 动态代理实现前言 学习 Spring 的过程中,不可避免要掌握代理模式。这篇文章总结一下代...
    99+
    2024-04-02
  • java中JDK动态代理的原理是什么
    这篇文章将为大家详细讲解有关java中JDK动态代理的原理是什么,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。Java可以用来干什么Java主要应用于:1. web开发;2. Android...
    99+
    2023-06-14
  • 一文读懂Java中动态代理的原理
    一文读懂Java中动态代理的原理?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。Java动态代理分析及理解代理设计模式定义:为其他对象提供一种代理以控制对这个对象的访问。动态...
    99+
    2023-05-31
    java 动态代理 ava
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作