动态代理

动态代理

动态代理的特点

字节码随用随创建,随用随加载。

它与静态代理的区别也在于此。因为静态代理是字节码一上来就创建好,并完成加载。

装饰者模式就是静态代理的一种体现。

动态代理的两种方式

一、基于接口的动态代理

提供者:JDK 官方的 Proxy 类。

要求:被代理类最少实现一个接口。

在这里插入图片描述

在此模拟一个经纪人和演员之间的关系

所谓代理,就是代替别人去做事情,比如经纪人就要代演员去谈合同,去处理事务

上图为一个接口,接口中的两个方法,代表了两种表演的方式,即常规的和危险的

在这里插入图片描述

假设上图为一个演员,经纪人和他即为代理和被代理的关系

基于jdk实现的动态代理,被代理类必须至少实现一个接口,也叫基于接口的动态代理

讲的通俗一点,代理模式就是将增强方法的方法体和原有的方法体相结合,在内存中生成一个结合后的字节码文件,但是这个文件看不见摸不着,并不是物理存在的,当字节码文件被读取后就会释放掉。

动态代理就是只有在用到生成的字节码文件时会加载,静态代理会一开始就加载好字节码文件

下面,我们写一个测试类来实现一下动态代理(这里就直接用main方法,不使用junit测试了)

public static void main(String[] args) {

	Actor actor = new Actor();

	IActor iActor =(IActor)Proxy.newProxyInstance(actor.getClass().getClassLoader(),            actor.getClass().getInterfaces()  , new InvocationHandler() {

		@Override

		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

			String name = method.getName();

			Float money = (Float) args[0];

			Object rtValue = null; 

			if ("basicAct".equals(name)){

					if (money > 2000){

						rtValue = method.invoke(actor,money/2);                        

					}                    

			}

			if ("dangerAct".equals(name)){

				if (money > 8000){

				rtValue = method.invoke(actor,money/2);                        

				}                   

			}

			return rtValue;                

		}

	}); 

	iActor.basicAct(5000f); 

	iActor.dangerAct(50000f); 

}

在上面的代码中,很明显可以看出actor就是被代理的对象

在创建代理对象的实例化时,用到了三个参数,分别是被代理对象的类加载器(ClassLoader),接口(Interfaces),和一个invocationHandle的匿名内部类(这也就是为什么基于JDK的动态代理为什么必须实现接口的原因)

在匿名内部类中,通过method.getName()方法获取方法名,通过对方法名的判断,可以对指定的方法进行增强,而通过args[]可以获得想要获得的参数(索引从0开始)

可以看出invoke方法返回值为一个object,所以先创建一个空对象,用来接收invoke方法的返回值

在上述的例子中,假定经纪人会扣取演员一半的费用,所以对方法的增强就是将传入的参数money除以2

而如果没有进行方法增强,演员会得到所有的费用

同理,在invoke方法中,也可以对方法进行别的增强

下图就是增强后的运行结果
在这里插入图片描述

二、基于子类的动态代理

提供者:第三方的 CGLib,如果报 asmxxxx 异常,需要导入 asm.jar。

要求:被代理类不能用 final 修饰的类(最终类)。

基于cglib实现的动态代理,并不要求被代理类必须实现接口,只要求其不能用final修饰

下图就是基于cglib实现的动态代理的被代理类

在这里插入图片描述

下面写一个main方法来测试一下

在这里插入图片描述

可以看出,基于cglib的动态代理,用到了第三方jar包中的Enhancer类中的create方法,与基于jdk的实现方式不同的是并没有用到接口

两种动态代理实现方式的选择

已经很明显了,如果被代理的类实现了接口的话,就要用基于JDK的方式,如果没有就要用到基于cglib的方式

动态,说到底指的是字节码文字的加载是动态的,spring的aop底层就用到了动态代理

欢迎各位大佬指导修正,接下来的一段时间我会每天分享对spring的一些感悟和踩过的很多坑,望大佬们能帮忙解答很多我解决不了的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值