以静态代理理解代理模式,从代理模式理解JAVA动态代理的底层原理
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了以静态代理理解代理模式,从代理模式理解JAVA动态代理的底层原理,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含6891字,纯文字阅读大概需要10分钟。
内容图文
动态代理
2020年12月23日
15:39
目录 |
- - 概述 - 1. 代理模式 - 2. 静态代理案例 - 3. 动态代理 - 3.1 案例 - 3.2 底层原理
|
概述
理解动态代理首先要理解代理模式,理解代理模式可以以静态代理案例为切入点。
JDK动态代理就是典型的动态代理的实现。
1. 代理模式
代理模式是什么?简单来说,代理模式的目的是不改变代理类的前提下对其做增强。
这个类图很吓人,实际上很简单,就是RealSubject实现了Subject,为了对RealSubject做增强,我们加入代理类Proxy,它同样实现了Subject,同时代理类持有RealSubject,这样一来,我们就可以在RealSubject的上下文做增强了。
其实本质上就是一个简单的组合,给RealSubject裹了又一层Subject的子类,理解这件事,很重要。
上述说明如果太过抽象,下面来从一个静态代理的案例入手,看完再回头看代理模式,就非常好理解了。
2. 静态代理案例
1 public interface SmsService { 2 String send(String message); 3 } 4 public class SmsServiceImpl implements SmsService { 5 public String send(String message) { 6 System.out.println("send message:" + message); 7 return message; 8 } 9 } |
上述是很普通的一个接口和它的实现类,只要我们愿意,随时都可以实现一个代理,对它做增强。
1 public class SmsProxy implements SmsService { 3 private final SmsService smsService; 5 public SmsProxy(SmsService smsService) { 6 this.smsService = smsService; 7 } 8 9 @Override 10 public String send(String message) { 11 //调用方法之前,我们可以添加自己的操作 12 System.out.println("before method send()"); 13 smsService.send(message); 14 //调用方法之后,我们同样可以添加自己的操作 15 System.out.println("after method send()"); 16 return null; 17 } 18 } |
上述的SmsService 即是任意的Subject,SmsServiceImpl 则是我们真实的RealSubject,而SmsProxy 就是我们的代理类了。
所以,代理模式其实非常简单,就是套一层父类实现。
3. 动态代理
代理类的编写很无聊,除了增强方法部分的代码,例如send,其他几乎都是重复工作。很多时候我们并不想要自己来编写。能不能我们只实现增强代码,其他工作由JAVA帮我们实现,例如写一个代理类。这就是JAVA的动态代理机制。
ps,如果往后继续学的话,会发现大量的框架是基于动态代理机制,原因是它的动态生成的特性,这里并不需要纠结。只需要理解动态代理机制本身即可,而理解动态代理机制,理解JAVA动态代理机制即可一叶知秋。
3.1 案例
以下会从案例出发,首先不要管内部的原理,只需要先知道代码的运行逻辑。
首先,和静态代理相同的subject和RealSubject。
1 public interface SmsService { 2 String send(String message); 3 } 4 public class SmsServiceImpl implements SmsService { 5 public String send(String message) { 6 System.out.println("send message:" + message); 7 return message; 8 } 9 } |
然后需要编写增强的逻辑,JAVA动态代理机制是通过实现InvocationHandler来实现的。
这里造成困惑,但是只需要先理解它是做什么的,以及,它会在代理类调用代理方法的时候被调用即可。
1 public class DebugInvocationHandler implements InvocationHandler { 2 /** 3 * 代理类中的真实对象 4 */ 5 private final Object target; 7 public DebugInvocationHandler(Object target) { 8 this.target = target; 9 } 11 // proxy是代理类Proxy,target是RealSubject,method是我们RealSubject的代理方法 12 public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException { 13 //调用方法之前,我们可以添加自己的操作 14 System.out.println("before method " + method.getName()); 15 Object result = method.invoke(target, args); 16 //调用方法之后,我们同样可以添加自己的操作 17 System.out.println("after method " + method.getName()); 18 return result; 19 } 20 } |
如何使用呢?很简单
- 先让Proxy帮我们new一个代理类
- 调用代理方法
1 public class Main { 2 public static void main(String[] args) { 3 // targets 是实际上的业务,RealSubject 4 SmsService target = new SmsServiceImpl(); 5 // JdkProxyFactory做的事很简单,利用jdk动态代理机制给我们生成一个代理类的实例 6 SmsService smsService = (SmsService) JdkProxyFactory.getProxy(target); 7 // 调用代理方法 8 smsService.send("java"); 9 } 10 } |
上面的方法使用了JdkProxyFactory,其实它并不重要,它只是调用api,让proxy帮我们创建了一个代理对象而已。
具体细节如下:
1 public class JdkProxyFactory { 2 public static Object getProxy(Object target) { 3 return Proxy.newProxyInstance( 4 target.getClass().getClassLoader(), // 目标类的类加载器 5 target.getClass().getInterfaces(), // 代理需要实现的接口,可指定多个 6 new DebugInvocationHandler(target) // 代理对象对应的自定义 InvocationHandler 7 ); 8 } 9 } |
总结
JAVA代理机制的使用:
- 业务接口,业务接口的实现
- 实现handler,即增强代码
- Proxy接口,new出代理对象,调用代理方法
JAVA代理机制代码的运行逻辑:
- Proxy创建了代理类
- 我们调用代理类的代理方法
- 代理方法调用handler,即我们的实现
3.2 底层原理
上面的案例的使用是很简单的,但是有些地方会很让人费解。它内部究竟发生了什么?
1 public class Main { 2 public static void main(String[] args) { 4 SmsService target = new SmsServiceImpl(); 6 SmsService smsService = (SmsService) JdkProxyFactory.getProxy(target); 9 } 10 } |
尤其是Main中,为何我们调用smsService的send,为什么会调用到handler里面的send呢?尽管传入了SmsServiceImpl,但我们并没有在其中调用handler的代码啊。
这里是一个理解的关键节点,也是起点。
JdkProxyFactory.getProxy(target) 这段代码返回的并不是我们的业务实现(SmsServiceImpl),而是另一个实现了SmsService接口的Proxy类,该类是JAVA给我们生成的。再回头看看,这不就是代理模式。
内部到底发生了什么?从上述逻辑来看,自动生成的Proxy类,应该就是下面这样的。
1 class Proxy#1 implements SmsService { 2 // 接收的是我们实现的DebugInvocationHandler,它持有target,即我们的目标代理类 3 InvocationHandler h; 4 // 接收接口和类加载器等信息 5 ... 6 // 初始化方法,通过类对象,接口初始化方法 7 Method method 9 // 注意,传入的参数由args接收,再传给handler 10 public void send(Object[] args){ 11 h.invoke(this, method, args); 12 } 13 } |
其实核心就是通过我们传递的父类接口信息,target被代理对象,增强代码handler,给我们创建了上面的代理类(再强调,它实现了SmsService)。
看我们的传入参数:
Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new DebugInvocationHandler(target)
这个Proxy类的创建,可以说就是动态代理的核心了:
- 它实现了Subject
- 持有handler,handler持有被代理对象
- 代理方法中调用handler.invoked
JAVA反射允许我们获得类的所有属性,所有方法,调用所有属性,所有方法。所以它才可以帮助我们动态编写Proxy类(实际上非常简单,最容易的方式,用字符串拼接,然后调用编译都能生成)。
内容总结
以上是互联网集市为您收集整理的以静态代理理解代理模式,从代理模式理解JAVA动态代理的底层原理全部内容,希望文章能够帮你解决以静态代理理解代理模式,从代理模式理解JAVA动态代理的底层原理所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。