广告
返回顶部
首页 > 资讯 > 精选 >Java如何实现JDK动态代理
  • 427
分享到

Java如何实现JDK动态代理

2023-07-02 14:07:34 427人浏览 安东尼
摘要

这篇文章主要讲解了“Java如何实现jdk动态代理”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java如何实现JDK动态代理”吧!概念代理:为控制A对象,而创建出新B对象,由B对象代替执行

这篇文章主要讲解了“Java如何实现jdk动态代理”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java如何实现JDK动态代理”吧!

概念

代理:为控制A对象,而创建出新B对象,由B对象代替执行A对象所有操作,称之为代理。一个代理体系建立涉及到3个参与角色:真实对象(A),代理对象(B),客户端。

其中的代理对象(B)起到中介作用,连通真实对象(A)与客户端,如果进一步拓展,代理对象可以实现更加复杂逻辑,比如对真实对象进行访问控制。

案例

需求:员工业务层接口调用save需要admin权限,调用list不需要权限,没权限调用时抛出异常提示。

静态代理

public interface IEmployeeService {    void save();     void list();}
public class EmployeeServiceImpl implements IEmployeeService {    @Override    public void save() {        System.out.println("EmployeeServiceImpl-正常的save....");    }    @Override    public void list() {        System.out.println("EmployeeServiceImpl-正常的list....");    }}
public class SessionHolder {    private static String currentUser;    public static String  getCurrentUser(){        return currentUser;    }    public static void   setCurrentUser(String currentUser){        SessionHolder.currentUser = currentUser;    }}
public class EmployeeProxy implements IEmployeeService {    //真实对象    private EmployeeServiceImpl employeeService;    public EmployeeProxy(EmployeeServiceImpl employeeService){        this.employeeService = employeeService;    }    @Override    public void save() {        //权限判断        if("admin".equals(SessionHolder.getCurrentUser())){            employeeService.save();        }else{            throw new RuntimeException("当前非admin用户,不能执行save操作");        }    }    @Override    public void list() {        employeeService.list();    }}
public class App {    public static void main(String[] args) {        System.out.println("----------------真实对象--------------------");        EmployeeServiceImpl employeeService = new EmployeeServiceImpl();        employeeService.list();        employeeService.save();        System.out.println("----------------代理对象--------------------");        SessionHolder.setCurrentUser("dafei");  //设置权限(当前登录用户)        EmployeeProxy employeeProxy = new EmployeeProxy(employeeService);        employeeProxy.list();        employeeProxy.save();    }}
----------------真实对象--------------------EmployeeServiceImpl-正常的list....EmployeeServiceImpl-正常的save....----------------代理对象--------------------EmployeeServiceImpl-正常的list....Exception in thread "main" java.lang.RuntimeException: 当前非admin用户,不能执行save操作at com.langfeiyes.pattern.proxy.demo.EmployeeProxy.save(EmployeeProxy.java:20)at com.langfeiyes.pattern.proxy.demo.App.main(App.java:16)

使用真实对象EmployeeServiceImpl 直接调用时,不管是list 还是save都能直接访问,但不符合需求上的admin权限限制。如果使用代理对象EmployeeProxy,可以完成需求实现。

通过直接创建新类新类代理对象方式完成代理逻辑,这种方式称之为静态代理模式。

JDK动态代理模式

Java常用的动态代理模式有JDK动态代理,也有cglib动态代理,此处重点讲解JDK的动态代理

还是原来的需求,前面的IEmployeeService EmployeeServiceImpl SessionHolder 都没变,新加一个JDK代理控制器-EmployeeInvocationHandler

public class EmployeeInvocationHandler  implements InvocationHandler {    //真实对象-EmployeeServiceImpl    private Object target;    public EmployeeInvocationHandler(Object target){        this.target = target;    }    //获取JVM在内存中生成代理对象    public Object getProxy(){        return  Proxy.newProxyInstance(                target.getClass().getClassLoader(),                target.getClass().getInterfaces(),                this);    }    //代理对象控制执行方法    //参数1:代理对象    //参数2:真实对象的方法(使用方式得到方法对象)    //参数3:真实对象方法参数列表    //此处是代理对象对外暴露的可编辑的方法处理场所,代理对象每调用一个次方法,就会执行一次invoke    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        String name = method.getName();        if("save".equals(name) && !"admin".equals(SessionHolder.getCurrentUser())){            throw new RuntimeException("当前非admin用户,不能执行save操作");        }        return method.invoke(target, args);    }}

测试App类稍微改动下:

public class App {    public static void main(String[] args) {        System.out.println("----------------真实对象--------------------");        EmployeeServiceImpl employeeService = new EmployeeServiceImpl();        employeeService.list();        employeeService.save();         System.out.println("----------------代理对象--------------------");        SessionHolder.setCurrentUser("dafei");        EmployeeInvocationHandler handler =             new EmployeeInvocationHandler(employeeService);        IEmployeeService proxy = (IEmployeeService) handler.getProxy();        proxy.list();        proxy.save();     }}

上面代码一样可以实现需求,跟静态代理区别就在于少创建了代理对象。此时存在疑问点,没有创建代理对象,为啥可以实现代理类调用呢??

原理分析

先抛出结论JDK动态代理底层实现原理:使用接口实现方式,运行时,在内存中动态构建出一个类,然后编译,执行。这个类是一次性的,JVM停止,代理类就消失。

参与角色 要理解JDK动态代理原理,首先得了解JDK动态代理涉及到的类

Java如何实现JDK动态代理

InvocationHandler:真实对象方法调用处理器,内置invoke方法,其功能:为真实对象定制代理逻辑

EmployeeInvocationHandler:员工服务真实对象方法调用处理器,此类有3个用途: 1>设置真实对象

     //真实对象-EmployeeServiceImpl    private Object target;    public EmployeeInvocationHandler(Object target){        this.target = target;    }

2>定制代理方法实现逻辑

为真实对象save方法添加了权限校验逻辑

    //代理对象控制执行方法    //参数1:代理对象    //参数2:真实对象的方法(使用方式得到方法对象)    //参数3:真实对象方法参数列表    //此处是代理对象对外暴露的可编辑的方法处理场所,代理对象每调用一个次方法,就会执行一次invoke    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        String name = method.getName();        if("save".equals(name) && !"admin".equals(SessionHolder.getCurrentUser())){            throw new RuntimeException("当前非admin用户,不能执行save操作");        }        return method.invoke(target, args);    }

3>返回代理对象

方法执行完之后,返回一个名为:$ProxyX的代理类(其中的X是序号,一般默认为0),这代理类由JDK动态构建出来。

    //获取jvm在内存中生成代理对象    public Object getProxy(){        return  Proxy.newProxyInstance(                target.getClass().getClassLoader(),                target.getClass().getInterfaces(),                this);    }

Proxy:动态代理控制类,是JDK动态生成的$ProxyX类的父类,它作用如下:
1>通过调用ProxyBuilder 类builder方法构建代理对象类

private static Constructor<?> getProxyConstructor(Class<?> caller,                                                      ClassLoader loader,                                                      Class<?>... interfaces){            return proxyCache.sub(intf).computeIfAbsent(                loader,                (ld, clv) -> new ProxyBuilder(ld, clv.key()).build()            );}

2>通过newProxyInstance方法返回$ProxyX类的实例

   public static Object newProxyInstance(ClassLoader loader,                                          Class<?>[] interfaces,                                          InvocationHandler h) {    //...   }

$Proxy0:App类运行时,JDK动态构建出来的代理类,继承至Proxy类

public class App {    public static void main(String[] args) {        //System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");        System.setProperty("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");        System.out.println("----------------真实对象--------------------");        EmployeeServiceImpl employeeService = new EmployeeServiceImpl();        employeeService.list();        employeeService.save();        System.out.println("----------------代理对象--------------------");        SessionHolder.setCurrentUser("dafei");        EmployeeInvocationHandler handler =                      new EmployeeInvocationHandler(employeeService);        IEmployeeService proxy = (IEmployeeService) handler.getProxy();        proxy.list();        proxy.save();     }}

默认情况下JVM是不保存动态创建代理类字节码对象的,可以在main方法中配置代理参数让字节码保留

//JDK8之前System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");//JDK8之后System.setProperty("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");

执行完之后,会在项目根目录生成代理类字节码对象。 

Java如何实现JDK动态代理

为了方便解读,将一些不需要的方法剔除之后

$Proxy0类

public class $Proxy0 extends Proxy implements IEmployeeService {    private static Method m4;    private static Method m3;    static {        try {            m4 = Class.forName("com.langfeiyes.proxy.demo.IEmployeeService")                 .getMethod("save");            m3 = Class.forName("com.langfeiyes.proxy.demo.IEmployeeService")                 .getMethod("list");        } catch (Exception e) {            e.printStackTrace();        }    }    public $Proxy0(InvocationHandler var1) throws Throwable {        super(var1);    }    public final void save() throws Throwable {        super.h.invoke(this, m4, (Object[])null);    }     public final void list() throws  Throwable{        super.h.invoke(this, m3, (Object[])null);    }}

从源码上看,$Proxy0的特点:

  • 1>继承了Proxy类,实现了IEmployeeService 接口

  • 2>通过静态块的方式反射IEmployeeService接口save与list方法,得到他们的方法对象Method

  • 3>调用父类构造器,需要传入InvocationHandler 参数

  • 4>重写IEmployeeService接口的save list方法靠的是父类Proxy的h属性.invoke方法

真相大白

下图所有参与动态代理的类:

Java如何实现JDK动态代理

 下图是上图的操作时序图,跟着走就对了

Java如何实现JDK动态代理

感谢各位的阅读,以上就是“Java如何实现JDK动态代理”的内容了,经过本文的学习后,相信大家对Java如何实现JDK动态代理这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

--结束END--

本文标题: Java如何实现JDK动态代理

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

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

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java如何实现JDK动态代理
    这篇文章主要讲解了“Java如何实现JDK动态代理”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java如何实现JDK动态代理”吧!概念代理:为控制A对象,而创建出新B对象,由B对象代替执行...
    99+
    2023-07-02
  • Java——JDK动态代理
    1.动态代理 1.1什么是动态代理? 动态代理(理解) 基于反射机制 举个例子,生活中一般在打官司的时候都会请代理律师,为什么要请律师呢?是因为开庭的时候大部人对于打官司没有经验,只会说出自己案件的陈述,并不会根据法律等争取自己权益...
    99+
    2023-08-31
    java 开发语言
  • Java实现JDK动态代理的原理详解
    目录概念案例静态代理JDK动态代理模式原理分析真相大白概念 代理:为控制A对象,而创建出新B对象,由B对象代替执行A对象所有操作,称之为代理。一个代理体系建立涉及到3个参与角色:真实...
    99+
    2022-11-13
  • java jdk动态代理详解
    jdk动态代理要对一个类进行代理,被代理的类必须实现至少一个接口,并且只有接口中的方法才能被代理。 jdk实现动态代理一般分为三步: 1. 编写接口和实现类。 2. 写一个处理器,该...
    99+
    2022-11-15
    java jdk 动态代理
  • 纯手写实现JDK动态代理
    作者:张丰哲原文:https://www.jianshu.com/p/58759fef38b8前言在Java领域,动态代理应用非常广泛,特别是流行的Spring/MyBatis等框架。JDK本身是有实现动态代理技术的,不过要求被代理的类必须...
    99+
    2023-06-02
  • JDK动态代理,代理接口没有实现类,实现动态代理方式
    目录JDK动态代理,代理接口没有实现类,实现动态代理被代理的接口:代理对象:那么接下来测试一下:jdk动态代理为什么要接口先通过一个简单例子实现功能:编写测试方法:里面的getPro...
    99+
    2022-11-12
  • 在Java中实现JDK动态代理的原理是什么
    在Java中实现JDK动态代理的原理是什么?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一、什么是代理?代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对...
    99+
    2023-05-31
    java jdk 动态代理
  • JDK和CGLib动态代理怎么实现
    本篇内容介绍了“JDK和CGLib动态代理怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!前言:动态代理是一种常用的设计模式,广泛应用...
    99+
    2023-06-02
  • Java动态代理如何实现
    本篇内容介绍了“Java动态代理如何实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!JDK动态代理:利用反射机制生成一个实现代理接口的匿名...
    99+
    2023-06-30
  • 基于jdk动态代理和cglib动态代理实现及区别说明
    目录jdk动态代理和cglib动态代理实现及区别jdk动态代理实现cglib动态代理区别总结jdk动态代理和cglib动态代理实现及区别 代理模式是一种设计模式,提供了对目标对象额外...
    99+
    2023-05-19
    jdk动态代理 cglib动态代理 jdk和cglib动态代理区别
  • 深入理解java动态代理的两种实现方式(JDK/Cglib)
    什么是代理模式?代理模式:在调用处不直接调用目标类进行操作,而是调用代理类,然后通过代理类来调用目标类进行操作。在代理类调用目标类的前后可以添加一些预处理和后处理操作来完成一些不属于目标类的功能。为什么要使用代理模式?通过代理模式可以实现对...
    99+
    2023-05-31
    cglib jdk java
  • java中JDK动态代理的原理是什么
    这篇文章将为大家详细讲解有关java中JDK动态代理的原理是什么,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。Java可以用来干什么Java主要应用于:1. web开发;2. Android...
    99+
    2023-06-14
  • java动态代理(jdk与cglib)详细解析
    JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息...
    99+
    2022-11-15
    java jdk cglib
  • Java反射(JDK)与动态代理(CGLIB)详解
    目录一、反射二、动态代理1、JDK代理2、CGLIB代理3、JDK代理与CGLIB代理对比总结一、反射 概念:在运行状态中,对于任意的一个类,都能够知道这个类的所有字段和方法,对任意...
    99+
    2022-11-12
  • java动态代理实现代码
    目录1、代理模式2、动态代理3、原理研究4、应用5、总结1、代理模式 代理模式是常用的设计模式之一,也是开发中常见的设计模式。 简单的描述一下,代理模式就是将实现类隔离开,比如你想给...
    99+
    2022-11-12
  • jdk动态代理使用实例详解
    目录前言为什么需要代理java中常用的代理模式一、JDK 动态代理二、cglib静态代理三、spring中代理的使用总结前言 代理模式不管是JDK,spring框架,还是日常的开发中...
    99+
    2022-11-13
  • JAVA如何实现动态代理技术
    这篇文章主要为大家展示了“JAVA如何实现动态代理技术”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“JAVA如何实现动态代理技术”这篇文章吧。一、引出动态代理生活中代理应该是很常见的,比如你可以...
    99+
    2023-05-30
    java
  • Java中JDK动态代理的超详细讲解
    目录1. 什么是动态代理?2.动态代理的实现方式有几种?3. JDK动态代理4. CGLB动态代理5.动态代理的效率6.为什么要使用动态代理呢?7. JDK动态代理详细使用介绍总结1...
    99+
    2022-11-13
    Java jdk动态代理 java动态代理原理 jdk动态代理是如何实现的
  • 深度剖析java中JDK动态代理机制
    摘要相比于静态代理,动态代理避免了开发人员编写各个繁锁的静态代理类,只需简单地指定一组接口及目标类对象就能动态的获得代理对象。代理模式使用代理模式必须要让代理类和目标类实现相同的接口,客户端通过代理类来调用目标方法,代理类会将所有的方法调用...
    99+
    2023-05-31
    jdk 动态代理 ava
  • Java JDK与cglib动态代理有哪些区别
    本篇内容主要讲解“Java JDK与cglib动态代理有哪些区别”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java JDK与cglib动态代理有哪些区别”吧!一、说明sp...
    99+
    2023-07-05
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作