如果你始终不理解Java动态代理的设计目的,建议您来看看!

107 篇文章 10 订阅
61 篇文章 1 订阅

在文章:

一文读懂Java中的设计模式——代理模式,以翻译场景举例,特别通俗易懂!-CSDN博客

中给大家介绍了Java的代理模式,以及静态代理的用法。接下来就为大家介绍动态代理。注意:本文涉及的 类EnglishProxy 和FrenchProxy源码在上篇文章中。完整的java代理模式源码下载地址如下:https://download.csdn.net/download/liwenxiang629/88650205

JDK动态代理介绍

动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。JDK中关于动态代理的重要api如下:

  • java.lang.reflect.Proxy  这是Java 动态代理机制生成的所有动态代理类的父类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。 
  • static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) ,该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
  • java.lang.reflect.InvocationHandler  这是调用处理器接口,定义了一个invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。每次生成动态代理类对象时都要指定一个对应的调用处理器对象。Object invoke(Object proxy, Method method, Object[] args)  该方法负责集中处理动态代理类上的所有方法调用。第一个参数既是代理类实例,第二个参数是被调用的方法对象 ,第三个方法是调用参数。调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行
  • java.lang.ClassLoader  这是类装载器类,负责将类的字节码装载到Java 虚拟机(JVM)中并为其定义类对象,然后该类才能被使用。Proxy静态方法生成动态代理类同样需要通过类装载器来进行装载才能使用,它与普通类的唯一区别就是其字节码是由JVM 在运行时动态生成的而非预先存在于任何一个.class 文件中。 每次生成动态代理类对象时都需要指定一个类装载器对象。

所谓静态代理也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。 但是静态代理的缺点也很明显,在程序规模稍大时,维护代理类的成本高,静态代理无法胜任!那么在这里我们就通过动态代理来解决静态代理维护成本高的问题。

例如我们有一个新的需求,需要增加给翻译结算的功能,怎么做呢?

最简单的方法就是分别在代理类 EnglishProxy 和FrenchProxy的talk方法里增加方法。目前只有两个类,这么做是比较容易实现的,当涉及需要修改多个类的时候,显然这种方式就不合适了,我们就可以通过动态代理来实现这个需求!

核心类的设计如下:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class LanguageProxyHandler implements InvocationHandler {

	 private Object object;

	 public LanguageProxyHandler(Object p_object){	 
	        this.object = p_object;

	 
	    }
	 
	
	 @Override
		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
			
	          method.invoke(object, args);    
	          System.out.println("给翻译结算");
	          return null;
	 }
}

我们可以看到,动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)

最后来看测试代码

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class DynamicProxyTest {
    public static void main(String[] args) {
    	
    	
    	 ITalk vtalk = new EnglishProxy();
    	 
    	 //ITalk vtalk = new FrenchProxy(); 	
    	 
         InvocationHandler handler = new LanguageProxyHandler(vtalk);

         ITalk proxyTalk = (ITalk)Proxy.newProxyInstance(vtalk.getClass().getClassLoader(),vtalk.getClass().getInterfaces(), handler);

         proxyTalk.talk();
          

	}
}

输出:

找一个会汉语和英语的翻译
默认中文交流
翻译把汉语翻译成英语
给翻译结算

我们可以看到,在没有修改类EnglishProxy 和FrenchProxy的前提下就实现了需求

JAVA代理模式总结

通过JDK实现动态代理类也有小小的遗憾,那就是它只能为接口创建代理!如果想对没有实现接口的类创建代理则无能为力。为了解决这种情况,我们通常使用cglib技术,其在AOP(例如spring)和ORM(例如Hibernate)中有广泛的应用,在这里就不对cglib进行展开介绍了。Java代理模式关系总结如下:

我的每一篇文章都希望帮助读者解决实际工作中遇到的问题!如果文章帮到了您,劳烦点赞、收藏、转发!您的鼓励是我不断更新文章最大的动力!

  • 39
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

测试开发Kevin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值