JDK中的动态代理之一

JDK动态代理和CGLIB动态代理 在SpringAOP中基于动态代理实现功能的增强,也就是动态的生成代理类,在代理类中织入增强的逻辑然后调用目标对象的方法。动态代理中用的比较多的两种:JDK动态代理、CGLIB动态代理。 JDK动态代理 使用JDK的java.lang.reflect.Proxy类的newProxyInstance方法实现的代理。 用一个测试接口看下具体实现: public interface JdkProxyDemoService { void queryTrs(); } @Service public 阅读详情
JDK中的动态代理
       写到代理模式这章,不得不提到JDK中的动态代理,它是java语言自身对动态代理的支持,类似于JDK中在java.util包中提供Observable类和Observer接口提供对观察者模式的语言级支持。关于动态代理的好处可以从网络上流行的<<JAVA中用动态代理类实现记忆功能>>、<<使用JAVA中的动态代理实现数据库连接池>>、<<通过JAVA的动态代理机制控制事务>> 、<<用Java动态代理实现AOP>>……看出动态代理的优点――动态地为软件增加功能。应用的文章很多,出于自身的好奇我们来研究JDK中动态代理的实现吧!这就是本博客所谓的“任何东西只有精通了,才能更好地使用”,有别于所谓的“很好地使用它,然后再去精通它”。下面我们开始对java语言中动态代理的源代码的研究吧! 
一、动态代理的相关类
       JDK中和动态代理直接相关的主要有InvocationHandler接口和Proxy类。InvocationHandler接口相当于Proxy类的CallBack Interface。
 
 
三、Proxy类
Proxy 为动态代理类,是动态代理的核心类,其作用类似于代理模式中的代理。从上面的类图可以看出 Proxy 类中包含的全是静态的方法和成员变量,这是一个纯粹的工具类,因此其源代码中含有一个私有的构造器,在某种意义上可以看作为一个单例模式的特殊情形。(原因为: 1. 不能实例化; 2. 提供统一的入口)。这个类中包含很多很有意思的实现,下面我们还是看看其源代码吧! 
package java.lang.reflect;
import java.lang.ref.*;
import java.util.*;
import sun.misc.ProxyGenerator;            //sun将产生代理对象的类,放在sun.misc包中 
public class Proxy implements java.io.Serializable {                     //实现了Serializable接口,因此可以保存到流中
    private static final long serialVersionUID = -2222568056686623797L;   //序列化时使用的版本号 
         //以下的变量用于代理对象创建时,名称各部分的组合 
         //以下几个成员变量组合在一起,形成被创建的代理对象的名称
         //这些被ProxyGenerator创建的代理对象,以此名字,存入当前Proxy对象内部的cache中
         //被创建代理对象的名称包含3部分:
         //                          1.包名proxyPkg ;2.代理对象的名称前缀;3.代理被创建的数目num;
           //                          该数目表示当前被创建的代理对象是使用ProxyGenerator创建的第n个代理对象
         //下面是代理对象的名称前缀
          private final static String proxyClassNamePrefix = "$Proxy";
         //初始化时,代理被创建的个数为0
         private static long nextUniqueNumber = 0;
         //由于可能有多个客户同时使用ProxyGenerator创建代理对象,因此必须进行同步
         //                                   此同步过程使代理被创建的数目唯一
    private static Object nextUniqueNumberLock = new Object();
    //表示某个代理对象正在被创建
    private static Object pendingGenerationMarker = new Object(); 
    //代理对象实例化时需要的的构造参数
    private final static Class[] constructorParams ={ InvocationHandler.class }; 
    //类转载器的cache
    private static Map loaderToCache = new WeakHashMap(); 
   //所有已经被创建的代理对象的集合,每次要创建新的代理对象,都会先到该集合查找是否存在
   //                  这其实是一个代理对象的缓存
    private static Map proxyClasses =Collections.synchronizedMap(new WeakHashMap()); 
   protected InvocationHandler h;                           //唯一的非静态的成员变量,主要用于protected构造器 
    protected Proxy(InvocationHandler h) {   //protected构造器,给继承提供了可能
                   this.h = h;
    } 
    private Proxy() { }                       //工具类,不能实例化,因此为私有构造器 
         //使用特定的类加载器,加载某个类,从而得到此代理对象的Class
         public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)throws IllegalArgumentException{
                   if (interfaces.length > 65535) {                  //构造器太多,抛出异常
                       throw new IllegalArgumentException("interface limit exceeded");
                   }
                   Class proxyClass = null;                //初始化一个Class
                   //将interface的名字 collect interface names to use as key for proxy class cache */
                   String[] interfaceNames = new String[interfaces.length];
                   Set interfaceSet = new HashSet();          //避免重复
                   for (int i = 0; i < interfaces.length; i++) {
                       String interfaceName = interfaces[i].getName();                  //得到名称
                       Class interfaceClass = null;
                       try {
                                     interfaceClass = Class.forName(interfaceName, false, loader); //使用类装载器转载类
                       } catch (ClassNotFoundException e) {   }
                       if (interfaceClass != interfaces[i]) {            //两者不等抛出异常
                                     throw new IllegalArgumentException(interfaces[i] + " is not visible from class loader");
                       }
                       if (!interfaceClass.isInterface()) {                        //不是接口抛出异常
                                     throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface");
                       }
                       if (interfaceSet.contains(interfaceClass)) {         //已经存在抛出异常
                                     throw new IllegalArgumentException("repeated interface: " + interfaceClass.getName());
                       }
                       interfaceSet.add(interfaceClass);                       //不存在则放入hashset中
                       interfaceNames[i] = interfaceName;                  //置换输入中的构造器
                   }       
                   Object key = Arrays.asList(interfaceNames);   //将上面的数组转化为List对象
                   //以上完成对构造器的处理 
                   Map cache;
                   synchronized (loaderToCache) {                               //同步化类装载器的Cache
                       cache = (Map) loaderToCache.get(loader);
                       if (cache == null) {
                                     cache = new HashMap();                       //该Cache以类装载器为key,value也为一个Cache
                                     loaderToCache.put(loader, cache);
                       }
                   }
                   synchronized (cache) {
                      do {
                            Object value = cache.get(key);                         //该Cache以Class数组为key以proxyClass为value
                            if (value instanceof Reference) {
                                proxyClass = (Class) ((Reference) value).get();   // 保存在 Cache 中的 value 为 Reference
                            }
                            if (proxyClass != null) {                                               //代理对象存在
                                return proxyClass;                                             //返回此proxyClass
                            } else if (value == pendingGenerationMarker) {
                                try {
                                               cache.wait();                                   //其它线程正在创建代理对象,则本线程等待
                                } catch (InterruptedException e) {   }
                                continue;
                            } else {
                                cache.put(key, pendingGenerationMarker);
                                break;
                            }
                       } while (true);
                   }         
                   try {
                       String proxyPkg = null;                                               // 代理对象所在的包
                       for (int i = 0; i < interfaces.length; i++) {             //遍历Class数组
                                     int flags = interfaces[i].getModifiers();                //得到Class的修饰符
                                     if (!Modifier.isPublic(flags)) {                     //public的修饰符
                                         String >
                                         int n = name.lastIndexOf('.');
                                         String pkg = ((n == -1) ? "" : name.substring(0, n + 1)); //package名称
                                         if (proxyPkg == null) {
                                                        proxyPkg = pkg;                             //
                                         } else if (!pkg.equals(proxyPkg)) {
                                                        throw new IllegalArgumentException( "non-public interfaces from different packages");
                                         }
                                     }
                       }//for
                       if (proxyPkg == null) {
                                     proxyPkg = "";             // 默认包名
                       }                    
                       {
                                     long num;
                                     synchronized (nextUniqueNumberLock) {                          //同步块
                                         num = nextUniqueNumber++;                                   //每次递增1
                                     }
                                     String proxyName = proxyPkg + proxyClassNamePrefix + num; //名称为三者的组合
                                     //以下是创建ProxyClass的过程
                                     byte[] proxyClassFile =ProxyGenerator.generateProxyClass(proxyName, interfaces);
                                     // 上面是使用 ProxyGenerator 将指定名称代理类的 .class 文件转化为 byte 数组
                                     // 在类加载器中进一步执行此 .class 文件,在 java 语言中经常称 java 为解释型语言
                                     // 字节码就是被解释的中间代码,它是独立于平台的,其执行是在虚拟机上
                                     //                                   有兴趣的朋友多研究研究编译原理、以及虚拟机的实现
                                     //                                   sun 已经将其 Compiler 和 VM 的源代码开源了,有能力可以研究研究
                                    / / 利用刚才产生的 byte 数组,使用类加载器产生此 ProxyClass 
                                     try {
                                               使用类装载器,装载指定名称的代理类
                                         proxyClass = defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);
                                     } catch (ClassFormatError e) {
                                         throw new IllegalArgumentException(e.toString());
                                     }
                       }
                       // 将新创建的ProxyClass放入Chche中
                       proxyClasses.put(proxyClass, null);      
                   } finally {
                       synchronized (cache) {
                                     if (proxyClass != null) {
                                         cache.put(key, new WeakReference(proxyClass));           //将此Renference放入cache中
                                     } else {
                                         cache.remove(key);
                                     }
                                     cache.notifyAll();                    //多线程的wait/notify机制
                       }
                   }
                   return proxyClass;
    } 
 
jdk动态代理实现原理 JDK 动态代理是什么 在了解JDK动态代理前,有需要可以了解下代理模式 参考:https://blog.youkuaiyun.com/yhl_jxy/article/details/52679882 JDK 的动态代理是基于拦截器和反射来实现的 JDK代理是不需要第三方库支持的,只需要 JDK 环境就可以进行代理,使用条件: 必须实现 InvocationHandler 接口 使用 Proxy.newProxyInstance 产生代理对象 被代理的对象必须要实现接口 JDK 动态代理简单实现 使用 JDK 动态 阅读详情

相关推荐

JDK 动态代理

定义目标接口(如)和目标类(如编写InvocationHandler 实现类:在invoke()中写增强逻辑 + 调用目标方法通过生成代理对象调用代理对象的方法:自动触发invoke(),完成增强 + 业务执行通过 JDK 动态代理,我们彻底告别了静态代理的冗余代码,实现了 “一次编写增强逻辑,处处复用” 的优雅效果。这也是 Spring AOP 等框架的核心底层技术之一,掌握它能帮你更深入理解框架的设计思想。

ysct_999的博客 4540

Java——JDK动态代理

动态代理是指代理类对象在程序运行时由JVM根据反射机制动态生成的。动态代理不需要定义代理类的,java源文件。动态代理其实就是jdk运行期间,动态创建class字节码并加载到JVM。动态代理的实现方式常用的有两种:使用JDK代理,与通过CGLlB动态代理。

m0_73671382的博客 7677

jdk动态代理和cglib动态代理对比

JDK 动态代理:只代理接口(interface),无法代理类。它使用java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口来实现动态代理。 CGLIB 动态代理:可以代理类和接口。它通过生成目标类的子类来创建代理对象,因此可以代理没有实现接口的类。

zfj321的博客 1544

JDK动态代理详解

可能很多小伙伴首次接触动态代理这个名词的时候,或者是在面试过程中被问到动态代理的时候,不能很好的描述出来,动态代理到底是个什么高大上的技术。不方,其实动态代理的使用非常广泛,例如我们平常使用的Spring中的注解,其依赖于AOP,而AOP的底层实现便是动态代理,看到这里,是不是更有兴趣去了解动态代理了呢?动态代理:可以分解为“动态”+“代理”。所以,静态代理存在一定的局限性,不能很好的满足需求的千变万化,动态代理的出现,就是为了解决这些局限性。

StoNENee的博客 4729

LWIP协议栈在STM32H7上的内存优化实战:如何用32KB RAM实现稳定千兆以太网通信

本文深入探讨了在STM32H7微控制器上,如何通过内存优化策略,在仅32KB的D2 SRAM中稳定运行LWIP协议栈以实现千兆以太网通信。文章详细分析了STM32H7的内存架构、LWIP的内存消耗瓶颈,并提供了从描述符表与PBUF池精确分配、链接脚本修改到MPU区域划分的一整套实战优化方案,旨在解决大数据量传输卡死等常见配置问题。

gg901的博客 605

window下迁移SVN仓库到新的windows服务器

window下迁移SVN仓库到新的windows服务器

Bertram的博客 4692

Java-JDK动态代理

介绍:我们需要掌握的程度动态代理(理解) 基于反射机制掌握的程度:1.什么是动态代理?2.动态代理能够做什么?后面我们在用Spirng和Mybatis的时候,要理解怎么使用的.代理,在我们日常生活之中就有体现,代购,中介,换ip,商家等等.比如有一家美国的大学,可以对全世界招生.留学中介(代理 )留学中介(代理):帮助这家美国的学校招生,中介是学校的代理中介是代替学校完成招生功能代理特点中介和代理他们要做的事情是一致的:招生中介是学校代理,学校是目标。

zhxingqi的博客 6358

LabVIEW电压信号采集系统:从零搭建到科研实战

本文详细介绍了如何从零开始搭建一个基于LabVIEW的电压信号采集系统。内容涵盖硬件选型(如NI USB-6002数据采集卡)、软件环境配置、核心程序开发(包括多通道同步采集、数据自动保存)以及高级功能优化。系统支持自定义采样率与时长,并提供了完整的LabVIEW程序框图和配套的Python数据分析脚本,旨在帮助科研人员和工程师快速构建稳定、高效的专属数据采集方案,提升实验自动化水平。

gold8的专栏 462

Spring高手之路17——动态代理的艺术与实践

本文深入分析了JDK和CGLIB两种动态代理技术在Spring框架中的应用。讨论了动态代理的基础概念,通过实例展示了如何实现和应用这两种方法,并比较了它们的性能差异及适用场景。进一步,探讨了在动态代理中实现熔断限流和日志监控的策略,以及如何利用动态代理优化Spring应用的设计和功能。

卓越无关环境,保持空杯心态——靡不有初,鲜克有终 1万+

从零开始跑通3DGS教程:(三)坐标系与尺度编辑(CloudCompare)

本文所属《从零开始跑通3DGS教程》系列文章; sfm重建的点云已经丢掉了尺度信息,并且坐标系跟图像数据有关(SFM初始化选择的图像),所以如果想恢复物理真实尺度,以及在想要的视角下渲染,那么需要对尺度和坐标系进行编辑修正,下文介绍如何使用CloudCompare修改坐标系和尺度

诺有缸的高飞鸟的博客 2871

【测开求职】面试题:计算机网络 详细版整理

本篇文章是笔者为准备研究生复试和校招而写,因此主要针对问答,注重理解,而不在于细节计算。读者可以先查看上面的链接走一遍计算机网络的整体框架结构。其中,重点难点以及易混淆的知识点,笔者会用其他文章进行了详述,在知识点处贴好了链接,有需要的可以查阅。

vector的博客 5937

JDK动态代理

个人理解: 就是当你写了一个接口,里面有方法,然后写了实现类实现方法,完成方法逻辑,然后有一天,想对这个方法进行修改,但是不想改源码,所以有两种方式可以实现。第一种是静态代理,创建一个类继承实现类,然后对方法进行修改,这样太局限,因为只能针对特定的类增强方法,有100个实现类就要创建100个子类去实现。第二种方式是动态代理,可以动态地生成代理类,这是可以接受的。 这篇文章记录的JDK动态代理 2.创建代理类 需要实现InvocationHandler接口,重写invoke方法,这里可以对方法进行增强。 3

weixin_46666822的博客 1万+

海康visionmaster-渲染结果:通过绑定流程或模块获取 渲染结果的方法

海康visionmaster-渲染结果:通过绑定流程或模块获取 渲染结果的方法

视觉人机器视觉的博客 2646

Java中的JDK动态代理

Java中JDK动态代理,AOP是对动态代理的进一步规范化,CGLB动态代理

weixin_44362089的博客 5562

10、高阶ΣΔ调制器设计与优化

本文深入探讨了高阶ΣΔ调制器的设计与优化技术,重点介绍了NTF零点优化方法,通过分散单位圆上的零点分布提升信噪失真比(SQNR)。文章分析了量化噪声耦合技术如何有效提高噪声整形阶数,并对比了CIFB、CIFF、CRFB和CRFF等不同架构的性能特点。同时,详细阐述了基于稳定性与性能权衡的设计流程,结合Schreier的Delta-Sigma Toolbox实现NTF综合与仿真验证。内容涵盖从理论推导到实际设计步骤,为高阶ΣΔ调制器的稳定性提升与性能优化提供了系统性指导。

tgb345678的博客 134

SAP-MM-采购过账接口(与WMS集成)-代码

1、判断传入值非空检验; 2、判断过账日期是否允许在当前期间; 3、判断是否为集采订单业务,是否审批完成; 4、判断是否发布标准成本发布(此业务场景与价格控制3+S有关) 5、保存日志表; 6、判断业务公司订单审批状态; 7、创建STO交货单、集采公司订单过账、STO公司间创建交货单、交货单过账(两步法)、过账失败回滚(冲销交货、删除交货单、冲销集采入库)

qq_32198063的博客 421

JDK动态代理、Cglib动态代理及Spring AOP

Java中的JDK动态代理是一种通过反射机制生成代理对象的技术,使得我们能够在运行时动态地创建某个接口的代理类,而无需手动编写实现类。JDK动态代理通常用于横切关注点(如日志、事务管理、安全性等)在方法调用前后进行处理,而不需要修改目标类的源代码。

意疏的博客 6385

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

JDK动态代理和CGLIB动态代理有什么区别?

JDK动态代理和CGLIB动态代理有什么区别?

水w的博客 8019

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

【Spring篇】JDK动态代理

代理类的作用居然是拦截作用,你敢相信?进来看不一样的jdk动态代理,让你从根本上理解动态代理

m0_64231944的博客 3349

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

深入理解JDK动态代理

深入理解JDK动态代理

abcafdsgr123456789的博客 1835

JDK动态代理源码解析

本篇从源码的角度,对JDK动态代理的实现,工作原理做简要分析。

西岭千秋雪的博客 1692

简单实现jdk的动态代理

简单实现jdk的动态代理 jdk动态代理的使用 package com.util; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class Test { //产生代理对象 public static ...

小王同学的博客 2070

SpringAOP JDK动态代理

目前我本人正在学习SpringFramework的知识,这也是这个专栏的主题。我前面的几篇博文中,简单的认识了一下SpringFramework,记录了SpringFramework的环境搭建,记录了SpringIOC如何加载配置文件,记录了SpringIOC三种Bean对象的实例化方法。还记录了SpringIOC手动装配(注入)的方法之一:set方法注入。还有另外三个不太常用的SpringIOC手动注入的方法。其实目前大部分都使用的是自动注入的方法,手动注入使用的不多。就算是使用手动注入的方法,使用的主流

weixin_46281472的博客 3303
上一篇: JDK开发工具包详解
下一篇: JDK中的动态代理之二
lhminjava
博客等级 码龄21年 15粉丝 6原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值