JDK动态代理的一些认识

JDK动态代理和CGLIB动态代理 在SpringAOP中基于动态代理实现功能的增强,也就是动态的生成代理类,在代理类中织入增强的逻辑然后调用目标对象的方法。动态代理中用的比较多的两种:JDK动态代理、CGLIB动态代理。 JDK动态代理 使用JDK的java.lang.reflect.Proxy类的newProxyInstance方法实现的代理。 用一个测试接口看下具体实现: public interface JdkProxyDemoService { void queryTrs(); } @Service public 阅读详情
         通过学习静态代理,知道如果接口增加了方法,那么委托类和代理类都必须实现,同时在代理类中还要对新增方法做处理,比如日志记录等,很繁琐。而JDK的动态代理就应运而生了,代理类不需要程序员手动预先写好,而是有Proxy类来帮你生成(运行期生成)。先直接看例子。
package proxy;

public interface SingInterface {
	public void sing();
}


package proxy;

public interface DanceInterface {
	public void dance();
}


package proxy;

public class Person implements SingInterface, DanceInterface {

	@Override
	public void dance() {
		System.out.println("I'm dancing......");
	}

	@Override
	public void sing() {
		System.out.println("I'm singging......");
	}

}


package proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * 给目标类(被代理类,委托类)的方法执行前和执行后做些日志
 *
 */
public class LogInvocationHandler implements InvocationHandler{

	private Object targer;//目标类
	public LogInvocationHandler(Object target){
		this.targer=target;
	}
	/**
	 * 取得有Proxy产生的代理类
	 */
	public Object getProxy(){
		return Proxy.newProxyInstance(
				/*取得当前线程使用的加载器*/Thread.currentThread().getContextClassLoader(),
				/*目标类都实现了哪些接口,告诉Proxy,Proxy生成的代理类也将会同样实现*/this.targer.getClass().getInterfaces(),
				/*将自身传给Proxy,Proxy生成的代理类将会用它调用下面的invoke方法*/this);
	}
	@Override
	/**
	 * proxy就是Proxy类生成的代理类
	 * 初步学习JDK的动态代理,这里最容不明白,到底是谁调用了它
	 */
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		System.out.println(method.getName()+"准备执行......");
		Object result=method.invoke(this.targer, args);//执行的是目标类的方法
		System.out.println(method.getName()+"执行结束......");
		return result;
	}

}



package proxy;
/**
 *测试类 
 *给Person的sing和dance方法执行前和执行后做些日志
 */
public class Client {

	public static void main(String[] args){
		Person person=new Person();
		//取得将对person进行加日志的代理类
		Object proxy=new LogInvocationHandler(person).getProxy();
		//对sing方法加日志
		((SingInterface)proxy).sing();
		//对dance方法加日志
		((DanceInterface)proxy).dance();//可知proxy一定同时实现了SingInterface和DanceInterface接口
		
	}
	
	
}

运行结果

sing准备执行......
I'm singging......
sing执行结束......
dance准备执行......
I'm dancing......
dance执行结束......

 

下面来看看Proxy.newInstance方法

public static Object newProxyInstance(ClassLoader loader,
			Class<?>[] interfaces, InvocationHandler h)
			throws IllegalArgumentException {
		if (h == null) {
			throw new NullPointerException();
		}

		/*
		 * Look up or generate the designated proxy class.
		 * 取得生成的代理类的Class类
		 */
		Class<?> cl = getProxyClass0(loader, interfaces); // stack walk magic:
															// do not refactor

		/*
		 * Invoke its constructor with the designated invocation handler.
		 */
		try {
			//取得代理类参数类型为InvocationHandler.class的构造方法
			final Constructor<?> cons = cl.getConstructor(constructorParams);
			final InvocationHandler ih = h;
			SecurityManager sm = System.getSecurityManager();
			if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
				// create proxy instance with doPrivilege as the proxy class may
				// implement non-public interfaces that requires a special
				// permission
				return AccessController
						.doPrivileged(new PrivilegedAction<Object>() {
							public Object run() {
								//把实现了InvocationHandler接口的对象给代理类
								//看上面的例子中LogInvocationHandler类中getProxy方法
								//里面获取代理类时,第三个参数是不是this(就是指logInvocationHandler)
								return newInstance(cons, ih);
							}
						});
			} else {
				return newInstance(cons, ih);
			}
		} catch (NoSuchMethodException e) {
			throw new InternalError(e.toString());
		}
	}

      看了上面的源码,得知重点转移到getProxyClass0(loader, interfaces); 这个方法里面了,进去看了 下,源码挺多的,重要的是后面那部分。

/*
	 * Generate the specified proxy class.
	 */
	byte[] proxyClassFile =	ProxyGenerator.generateProxyClass(
	    proxyName, interfaces);
	try {
	    proxyClass = defineClass0(loader, proxyName,
		proxyClassFile, 0, proxyClassFile.length);
	} catch (ClassFormatError e) {
	    /*
	     * A ClassFormatError here means that (barring bugs in the
	     * proxy class generation code) there was some other
	     * invalid aspect of the arguments supplied to the proxy
	     * class creation (such as virtual machine limitations
	     * exceeded).
	     */
	    throw new IllegalArgumentException(e.toString());
	}
    }
    // add to set of all generated proxy classes, for isProxyClass
    proxyClasses.put(proxyClass, null);

} finally {
    /*
     * We must clean up the "pending generation" state of the proxy
     * class cache entry somehow.  If a proxy class was successfully
     * generated, store it in the cache (with a weak reference);
     * otherwise, remove the reserved entry.  In all cases, notify
     * all waiters on reserved entries in this cache.
     */
    synchronized (cache) {
	if (proxyClass != null) {
	    cache.put(key, new WeakReference(proxyClass));
	} else {
	    cache.remove(key);
	}
	cache.notifyAll();
    }
}
return proxyClass;
}

     再继续跟踪ProxyGenerator.generateProxyClass(    proxyName, interfaces);


public static byte[] generateProxyClass(String paramString, Class[] paramArrayOfClass)
  {
    ProxyGenerator localProxyGenerator = new ProxyGenerator(paramString, paramArrayOfClass);
    byte[] arrayOfByte = localProxyGenerator.generateClassFile();
    if (saveGeneratedFiles)
      AccessController.doPrivileged(new PrivilegedAction(paramString, arrayOfByte)
      {
        public Object run()
        {
          try
          {
            FileOutputStream localFileOutputStream = new FileOutputStream(ProxyGenerator.access$000(this.val$name) + ".class");
            localFileOutputStream.write(this.val$classFile);
            localFileOutputStream.close();
            return null;
          }
          catch (IOException localIOException)
          {
          }
          throw new InternalError("I/O exception saving generated file: " + localIOException);
        }
      });
    return arrayOfByte;
  }


      到这就不再跟踪了,有兴趣的同学,可以自己去看源码吧。

      现在来看看Proxy给我们生成的代理类是怎样的。

package proxy;
import java.io.FileOutputStream;
import java.io.IOException;
import sun.misc.ProxyGenerator;
/**
 * 这个类来源http://rejoy.iteye.com/blog/1627405
 *
 */
public class ProxyGeneratorUtils {

	/**
	 * 把代理类的字节码写到硬盘上
	 * @param path 保存路径
	 */
	public static void writeProxyClassToHardDisk(String path) {
		
		// 获取代理类的字节码
		byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy11", Person.class.getInterfaces());
		
		FileOutputStream out = null;
		
		try {
			out = new FileOutputStream(path);
			out.write(classFile);
			out.flush();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				out.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args){
		ProxyGeneratorUtils.writeProxyClassToHardDisk("E:/$Proxy11.class");  
	}
}



    用反编译工具来看看生成出来的$Proxy11.class

 

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import proxy.DanceInterface;
import proxy.SingInterface;

public final class $Proxy11 extends Proxy
  implements SingInterface, DanceInterface
{
  private static Method m1;
  private static Method m4;
  private static Method m3;
  private static Method m0;
  private static Method m2;

  public $Proxy11(InvocationHandler paramInvocationHandler)
    throws 
  {
    super(paramInvocationHandler);
  }
  /**
   *由于 任何类都是Object的子类,所以Person类也拥有Object的方法
   *所以这里也进行了处理
   */
  public final boolean equals(Object paramObject)
    throws 
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

  public final void dance()
    throws 
  {
    try
    {
     //看到LogInvocationHandler中的invoke()方法是在这被调用的	
      this.h.invoke(this, m4, null);
      return;
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

  public final void sing()
    throws 
  {
    try
    {
      this.h.invoke(this, m3, null);
      return;
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

  public final int hashCode()
    throws 
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

  public final String toString()
    throws 
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m4 = Class.forName("proxy.DanceInterface").getMethod("dance", new Class[0]);
      m3 = Class.forName("proxy.SingInterface").getMethod("sing", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
    }
    throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
  }
}


    可以看到代理类实现了和目标类一样的接口,同时代理类调用了InvocationHandler中的invoke()方法,然后InvocationHandler中的invoke()方法调用目标类中的真正方法。

 


 



 
 
 
 
 
 
 
 
 

 

jdk动态代理实现原理 JDK 动态代理是什么 在了解JDK动态代理前,有需要可以了解下代理模式 参考:https://blog.csdn.net/yhl_jxy/article/details/52679882 JDK 的动态代理是基于拦截器和反射来实现的 JDK代理是不需要第三方库支持的,只需要 JDK 环境就可以进行代理,使用条件: 必须实现 InvocationHandler 接口 使用 Proxy.newProxyInstance 产生代理对象 被代理的对象必须要实现接口 JDK 动态代理简单实现 使用 JDK 动态 阅读详情

相关推荐

JDK 动态代理

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

ysct_999的博客 4540

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

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

意疏的博客 6385

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

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

zfj321的博客 1544

Java中的JDK动态代理

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

weixin_44362089的博客 5562

【AI智能体】图像处理-生成营销 Banner 图

生成营销 Banner 图是一款用于制作营销图片的智能体,它可以根据指定的营销活动内容,快速生成活动 Banner 图片,降低活动运营成本、提高制图效率。

AI创变工坊,和1000万新个体创业者一起成长!愿大家都能跟上时代的洪流,不被社会淘汰,愿大家的生活工作收入都能具备竞争力! 1175

ArcGIS天地图矢量化秘籍:用重分类+ArcScan高效提取建筑轮廓线

本文详细介绍了利用ArcGIS重分类和ArcScan技术高效提取天地图建筑轮廓线的半自动化流程。通过动态中断值计算、多级重分类策略和ArcScan高级矢量化技巧,显著提升城市规划中的矢量化效率与精度,适用于中级GIS用户。

weixin_30879169的博客 475

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

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

水w的博客 8019

银河麒麟V10开机卡Logo?别慌,手把手教你进单用户模式修复(附详细命令)

本文详细解析银河麒麟V10操作系统启动时卡Logo的故障原因,并提供进入单用户模式的完整解决方案。通过GRUB引导菜单修改启动参数,执行文件系统检查、图形服务修复等关键命令,帮助用户快速恢复系统正常运行,适用于运维人员和普通用户应对紧急启动问题。

weixin_30522183的博客 393

Java——JDK动态代理

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

m0_73671382的博客 7677

IMA知识库:从0到1的架构设计与实践

本文探讨了AI时代知识库系统的架构设计与演进路径。通过分析知识入库、知识管理和知识应用三大核心业务流程,提出了应对数据多样性、处理标准化、流量洪峰等挑战的解决方案。重点介绍了基于统一数据格式的解耦设计、异步处理架构、服务拆分策略以及权限安全体系,构建了一个稳定、高效且可扩展的知识库系统。文章强调优秀架构需要持续演进,通过识别薄弱点不断优化,最终实现技术方案与业务需求的平衡。

lovehu6686的博客 1738

huggingface下载提示huggingface_hub.errors.EntryNotFoundError:404 Client Error: (Request 1D: Root...如何解决?

🏆 本文收录于《全栈Bug调优(实战版)》专栏,致力于分享我在项目实战过程中遇到的各类Bug及其原因,并提供切实有效的解决方案。无论你是初学者还是经验丰富的开发者,本文将为你指引出一条更高效的Bug修复之路,助你早日登顶,迈向财富自由的梦想🚀!同时,欢迎大家关注、收藏、订阅本专栏,更多精彩内容正在持续更新中。让我们一起进步,Up!Up!Up!    备注: 部分问题/难题源自互联网,经过精心筛选和整理,结合数位十多年大厂实战经验资深大佬经验总结所得,数条可行方案供所需之人参考。

**My Coding Family** 1233

JDK动态代理详解

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

StoNENee的博客 4729

AI预测彩票,使用chatgpt和lstm神经网络(文末附源码)

AI预测彩票,使用chatgpt和lstm神经网络(文末有彩蛋)

淘淘小窝 1万+

JDK动态代理理解

代理模式说是一种“结构性设计模式” ,其核心思想是通过一个代理对象(proxy)间接访问目标对象(target),从而在不修改对象的前提下,实现对目标对象的控制或者功能增强。抽象角色: 定义目标对象和代理对象的共同接口(如java的接口)真实角色:实现抽象接口的具体业务逻辑类代理对象:持有真实角色的引用,并在其基础上拓展功能(如日志,事务等)举个例子:假设需要租房的时候,租客并不志杰联系房东,而是联系中介。

m0_60963435的博客 1834

地表最强之Android微信语音/腾讯会议通话录音

地表最强之Android微信语音/腾讯会议通话录音

cczhengv 6108

SAP FICO 科目余额查询表开发说明书(包括测试样例、程序代码仅作参考,不保证一定可以运行)

SAP FICO 科目余额查询表开发说明书(包括开发源代码、测试样例)

我好像病了的博客 1041

JDK动态代理源码解析

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

西岭千秋雪的博客 1692

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

JDK动态代理

JDK动态代理源码分析

qq_42145991的博客 915

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

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

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

深入理解JDK动态代理

深入理解JDK动态代理

abcafdsgr123456789的博客 1835

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

简单实现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动态代理是一种运行时创建代理类的技术,可以在不修改原始类代码的情况下为其添加新的功能。与静态代理不同,JDK动态代理不需要在编译时创建代理类,而是通过反射在运行时生成代理类。首先,我们定义一个接口,这个接口将由代理类实现。JDK动态代理是Java开发中一个非常有用的工具,可以在运行时为对象添加额外的功能,而无需修改原始代码。它主要通过Proxy类和InvocationHandler接口实现,具有很高的灵活性和扩展性。

qq_44266019的博客 1905
上一篇: JAVA静态代理为什么用聚合用接口
下一篇: cglib动态代理
夢_殤
博客等级 码龄15年 348粉丝 140原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值