JDK 动态代理是 java 反射的一个重要特性。它在某种方面为 java 提供了动态性的特性,给应用带来了无限的空间。大名鼎鼎的 Hessian 、 Spring AOP 基于动态代理实现。本文将简单的介绍 JDK 动态代理使用。

关于代理模式

代理模式是非常常用的一种设计模式,在我们的应用中经常被使用。一般场景是,我们有一个现成的类,它的功能比较的完善了,但是还是存在某些欠缺,这个时候我们需要去扩展一些新的功能,但又不想去重造轮子,这个时候可以使用代理类来替代原来的目标类,通过组合的模式,增加一种为目标类增加一些额外的功能。

代理模式的类结构图一般如下:

图1:代理模式类结构图

图2:代理模式序列图

JDK 动态代理

所谓 JDK 动态代理就是在运行时动态生成红色的代理类的过程。和静态代理不一样的地方是静态代理在编译期就要完成代理类 的实现。那么动态代理是如何实现的呢?

根据下面的例子,一步一步来看。

假设有这样一个接口 Speak:

  1. package proxy;
  2. public interface Speak {
  3. public void sayHello();
  4. }

实现类 PeopleSpeak.

  1. package proxy;
  2. public class PersonSpeak implements Speak {
  3. public void sayHello() {
  4. System.out.println("hello");
  5. }
  6. }

当我们去调用 PersonSpeak 的 sayHello 的时候,很显然是输出 hello 。现在我们需要通过动态代理在运行时动态的生成Speak 的代理类,并在调用 sayHello 方法的前后做一些输出。完成类似 aop 的功能。

根据以上的思路,我们需要有一个 PersonSpeak 的代理类,它持了 PersonSpeak 的对象,这样就能很方便的完成这个任务。如果用静态代理实现显然是很简单,那么用动态代理如何实现呢?

这个时候我们可以使用 java 反射里的 Proxy 类。此类是 JDK 动态代理的核心类。 Proxy 类拥有一个在运行期动态创建类的功能。动态的去创建一个 Speak 的子类,同时该子类持有 PersonSpeak 类的一个实例,该子类的功能就是实现上述第一部分代理类的功能。

关于 java 反射的 Method 、 Field 、 Class 、 Construtor 等这里不做介绍,重点介绍 Proxy和 InvocationHandler 类。

Proxy和InvocationHandler 类简介

Proxy 类提供了非常重要的方法,该方法能够动态的生成几个接口的实现类。具体的实现过程由 ProxyGenerator 类来实现,这是比较低层的一个类,这里不做过多描述。同时该动态类需要持有一个实现了 InvocationHandler 接口的子类对象。InvocationHandler 接口的子类对象是我们目标类的又一层代理。对于接口里面的每个方法实现,都是通过调用InvocationHandler 接口的子类对象的反射调用。也就是说动态代理类实际上是 InvocationHandler 子类对象的一个代理。那么 InvocationHandler 子类对象有时我们目标类的代理。通过这样层层代理我们就能实现上述的功能了。这句话可能不是很好理解,但是确实就是这么实现的,也许通过下面的图就能更好的理解:

图3:JDK动态代理调用过程

可以从上图看出来, JDK 动态反射并不是那么简单的一层代理,而是通过层层代理,最终通过 Method 的反射来调用目标对象的方法,而 aop 的实现可以放在 InvocationHandler 的是实现类里。

那么根据上述关于动态代理的简介,要实现 PersonSpeak 的 aop ,需要做两件事情

  1. 1.       实现一个持有 Speak 对象的 InvocationHandler 子类,改子类通过 Mechod 反射调用 PersonSpeak 的方法,并在调用方法前后实现 aop 功能。
  2. 2.       实现一个能动态创建 Speak 子类的代理类工厂,改工厂能动态的创建 Speak 子类。

具体实现如下:

  1. SpeakInvocationHandler ( 实现 InvocationHandler 接口 )

可以看出该类的 invoke 方法实现 aop 的关键,所有方法都是通过 invoke 来调用, invoke 内部通过反射来调用目标对象 target ,同时在调用前后实现了 aop 。

  1. package proxy;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. public class SpeakInvocationHandler implements InvocationHandler {
  5. public Object target;
  6. SpeakInvocationHandler(Object target) {
  7. this.target = target;
  8. }
  9. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  10. System.out.println(method.getName() + " invoked!");
  11. Object result = method.invoke(target, args);
  12. System.out.println(method.getName() + " return!");
  13. return result;
  14. }
  15. }
  1. ProxyFactory
  1. package proxy;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Proxy;
  4. public class ProxyFactory {
  5. Class             cls;
  6. InvocationHandler h;
  7. public ProxyFactory(String className, InvocationHandler h) {
  8. try {
  9. cls = Class.forName(className);
  10. this.h = h;
  11. } catch (ClassNotFoundException e) {
  12. e.printStackTrace();
  13. }
  14. }
  15. public Object createProxyObject() {
  16. return Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h);
  17. }
  18. }

ProxyFactory 主要是通过反射的 Proxy 类动态的去创建接口的子类,同时该子类是 InvocationHandler 的一个代理,所有的方法实现,都是通过 InvocationHandler 代理来调用。

最后来看下 Main 函数:

  1. package proxy;
  2. import java.lang.reflect.InvocationHandler;
  3. public class ProxyTest {
  4. public static void main(String args[]) {
  5. Speak s = new PersonSpeak();
  6. InvocationHandler h = new SpeakInvocationHandler(s);
  7. ProxyFactory proxyFactory = new ProxyFactory(PersonSpeak.class.getName(), h);
  8. Speak speakProxy = (Speak) proxyFactory.createProxyObject();
  9. speakProxy.sayHello();
  10. }
  11. }

得到的输出结果如下:

sayHello invoked!

hello

sayHello return!

从输出结果可以看出红色的输出部分正是我们通过动态代理来实现的。通过如上的过程完成了正果动态代理的过程。

除了实现 AOP ,动态代理还可以用于实现远程服务代理。比如说 Hessian 就是通过动态创建远程服务代理类来调用远程服务,从而使应用对远程服务透明化。 Hessian 调用过程如下:

图4:Hessian远程服务调用过程

总结

JDK 动态代理是 java 反射的一个非常重要的特性, JDK 动态代理类还可以用来作为 SOAP 的远程服务代理类,总之它在某种程度上提供了 java 的动态性的特点,为应用提供了很大的灵活性。

原文:http://blog.csdn.net/abing37/article/details/5449401

转载于:https://www.cnblogs.com/davidwang456/p/3942082.html

JDK动态代理实现简单AOP--转相关推荐

  1. JDK 动态代理的简单理解

    http://www.cnblogs.com/luotaoyeah/p/3778183.html JDK 动态代理的简单理解 动态代理 代理模式是 Java 中的常用设计模式,代理类通过调用被代理类的 ...

  2. AOP的底层实现-CGLIB动态代理和JDK动态代理

    AOP是目前Spring框架中的核心之一,在应用中具有非常重要的作用,也是Spring其他组件的基础.它是一种面向切面编程的思想.关于AOP的基础知识,相信多数童鞋都已经了如指掌,我们就略过这部分,来 ...

  3. AOP jdk动态代理

    一: jdk动态代理是Spring AOP默认的代理方法.要求 被代理类要实现接口,只有接口里的方法才能被代理,主要步骤是先创建接口,接口里创建要被代理的方法,然后定义一个实现类实现该接口,接着将被代 ...

  4. Javassist实现JDK动态代理

    提到JDK动态代理,相信很多人并不陌生.然而,对于动态代理的实现原理,以及如何编码实现动态代理功能,可能知道的人就比较少了.接下一来,我们就一起来看看JDK动态代理的基本原理,以及如何通过Javass ...

  5. spring中aop默认使用jdk动态代理,springboot2以后默认使用cglib来实现动态代理详解

    Spring5 AOP 默认使用 Cglib 了?我第一次听到这个说法是在一个微信群里: 真的假的?查阅文档 刚看到这个说法的时候,我是保持怀疑态度的. 大家都知道 Spring5 之前的版本 AOP ...

  6. AOP、ASPECT、Spring AOP、JDK动态代理、CGLib动态代理

    AOP.ASPECT.Spring AOP.JDK动态代理.CGLib动态代理 1 AOP介绍 1.1 基本定义 AOP(Aspect Oriented Programming)称为面向切面编程,它是 ...

  7. 两万字吐血总结,代理模式及手写实现动态代理(aop原理,基于jdk动态代理)

    代理模式及手写实现动态代理 一.代理模式 1. 定义 2. 示例 (1)静态代理 (2)动态代理 3. 通用类图 4. 代理模式的优点 二.jdk动态代理实现原理 1. jdk动态代理源码分析(通过该 ...

  8. 【spring】初识aop(面向切面编程) 使用jdk动态代理

    BankServiceIImple.java 代码实现: package com.zzxtit.aop;import java.math.BigDecimal;public interface Ban ...

  9. aop的四种增强以及JDK动态代理、Cglib动态代理

    动态代理 AOP底层实现:有接口自动应用的就是JDK动态代理 (1).JDK 在运行时运行时注入 本质:在内存中构建出接口的实现类 特点:被代理对象,必须有接口 实例: import java.lan ...

最新文章

  1. 用C#实现FTP搜索引擎
  2. 等概率随机函数的实现
  3. php jquery选择器,常用jQuery选择器总结_jquery
  4. python 笔记 :Gym库 (官方文档笔记)
  5. python粘贴代码到word_Python复制Word内容并使用格式设字体与大小实例代码
  6. vue企业项目demo_基于SpringBoot和Vue的企业级中后台开源项目
  7. HihoCode1721删除一个字符之后是回文字符串
  8. 英文求职信计算机网络,计算机网络专业毕业生英文求职信.doc
  9. jQuery禁止Ajax请求缓存
  10. Framework学习(三)之PMS、AMS、WMS
  11. python医疗_利用Python实现医疗在线问答机器人
  12. BZOJ2199[Usaco2011 Jan] 奶牛议会
  13. Android优雅地判断软键盘弹出状态
  14. 高分辨率图像剪切——目标检测
  15. 华为安装gsm框架_华为谷歌框架安装app下载-华为谷歌服务框架安装器(GMS安装器)下载v1.2.0 最新版-西西软件下载...
  16. window10安装虚拟机及相关软件
  17. 手机link.php,PHP中通过HTTP_USER_AGENT判断是否为手机移动终端的函数代码
  18. docker容器rename改名字
  19. ECharts地图api
  20. 记报错信息:java.lang.IllegalArgumentException: MALFORMED解决方案

热门文章

  1. mysql安全无密码登录_技术分享 | 安全地无密码登录 MySQL
  2. mipi和isp处理_VS-RK3399 在linux系统下面调试Mipi camera接口介绍
  3. Java高阶代码_Java高阶语法---Volatile
  4. java中怎么剪切文件_java中实现文件复制、剪切和删除
  5. php实现多商家开发,Thinkphp5.0实战-仿百度糯米开发多商家电商平台学习注意事项...
  6. oracle创建表语句_利用FME去拼接SQL语句并创建表
  7. go post 参数_go语言实现网易云音乐爬虫
  8. XGBoost相关知识-2
  9. python程序导入import、规范化和封装自己写的.py文件
  10. 文巾解题 182. 查找重复的电子邮箱