JAVA基础知识之JVM-——动态代理(AOP)

代理模式简介

在很多场景下,我们想使用一个类(通常是接口)A时,并不是直接使用这个类,而是通过另外一个类B去调用A的方法,这里的类B就是一个代理类。

有很多场景都会用到这种方法,例如假如创建类A需要很大的开销,我们会直接使用类B来代表类A。 又或者类A在远程主机上,我们没有权限直接调用A的方法,而代理类B却有权限,我们可以调用B从而访问到A。 又或者我们需要批量给A的方法加强一些功能,而我们没有权限修改A,或者修改A会导致其他关联的类因为耦合性需要修改,这时候我们也同样可以通过代理类B来增加功能。 这种间接访问A的方式就是一种非常常见的代理模式——通常我们只需要知道一个接口里提供了哪些方法,但并不需要方法细节,我们可以通过代理类来控制这些方法的调用,并满足例如前面提到的各种场景的功能要求。

动态代理

JAVA的代理模式大体上分为静态代理(编译期间就已经明确代理类及委托类的细节)和动态代理(在JVM中动态生成一个代理类,通过动态生成的代理类去访问委托类)。

动态代理也称为AOP模式,即面向切面编程。 实现AOP的方式有很多,目前主要有两种,一种是JDK自己实现的基于接口的动态代理,另一种是cglib方式,不需要强制实现接口。

本篇只简单介绍JDK自带的动态代理。

JDK动态代理

java动态代理主要涉及几个角色,目标类(接口-target),代理对象(proxy),处理器类(接口-InvocationHandler)。

实现原理大致是这样的,通过代理类proxy访问目标类target时,在JDK底层,会动态生成一个proxy类(其实是子类),同时让会让这个proxy类实现target接口,这个Proxy类包含一个InvocationHandler类型的成员变量,后面就会用处理器对象去初始化这个Proxy类对象。proxy中对target类所有的方法实现都交给InvocationHandler的实现类去处理,通过在proxy中重写target方法的实现,而在实现中直接调用InvocationHandler的invoke方法,这样就变成了我们调用代理proxy类执行target方法的时候,实际上是执行了InvocationHandler的invoke方法,而在invoke方法中,我们可以加入我们自己的逻辑,然后才调用真正的target中的方法。

整个过程可以用下面两段伪代码来模拟,

首先根据我们为proxy传入的参数(target所有接口方法,InvocationHandler实例),JDK会在底层动态地为我们创建一个代理类,代理类如下,

 1 class Proxy0 extends Proxy  implements target {
 2
 3   private Method m1;
 4
 5   //用InvocationHandler去初始化proxy, 后期就可以将proxy的代理的方法交给InvocationHandler去处理
 6   public Proxy0(InvocationHandler handler) {
 7
 8     supper(hander)
 9   }
10
11   public void setM1(Method m1) {
12
13     this.m1 = m1;
14   }
15
16   private void method1(Object para) {
17
18     this.hander.invoke(this, m1, new object[] {para});
19   }   
20
21 }

这段代理类的动态生成过程都由JVM控制,我们不可见(当然可以通过特殊方式拿到)。可以看到代理类会实现目标类target的所有方法,但是实现类中是调用了InvocationHandler的invoke方法的,这个invoke方法是需要我们自己去实现的,一般类似这样,

 1 class InvocationHandlerImpl implements InvocationHandler {
 2 private Object target; 3 @Override
 4 public Object invoke(Object proxy, Method method, Object[] args) {
 5 // 加入我们自己的代码
 6 ....
 7 //调用目标类的真正方法
 8 method.invoke(target, args);
 9 //加入我们自己的代码
10 .....
11 }

关键点在于第2行和第8行,使用了反射执行了目标类的真正需要被代理的方法。

以上整个过程,就是proxy代理的实现原理。

下面这张图片借用了别人的博客

下面是一个简单的例子,演示JDK动态代理的用法,

定义一个Dog接口, JDK的动态代理是基于接口的,其他动态代理可以基于继承的方式。

1 package aop;
2
3 public interface Dog {
4     void info();
5     void run();
6 }

为接口写个实现类,

 1 package aop;
 2
 3 public class GunDog implements Dog {
 4
 5     @Override
 6     public void info() {
 7         // TODO Auto-generated method stub
 8         System.out.println("我是一只猎狗");
 9     }
10
11     @Override
12     public void run() {
13         // TODO Auto-generated method stub
14         System.out.println("我奔跑迅速");
15     }
16
17 }

写个工具类,

 1 package aop;
 2
 3 public class DogUtil {
 4     public void method1() {
 5         System.out.println("====this is method1====");
 6     }
 7
 8     public void method2() {
 9         System.out.println("====this is method2====");
10     }
11 }

关键点,写一个处理器,实现InvocationHandler接口,

在invoke中加上我们自己的逻辑,再调用真正的target的方法。

后续代理类在处理target的所有方法时,都会在底层调用invoke方法,即将调用交给invoke了

 1 package aop;
 2
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Method;
 5
 6 public class MyInvocationHandler implements InvocationHandler {
 7
 8     private Object target;
 9
10     public void setTarget(Object target) {
11         this.target = target;
12     }
13
14     @Override
15     public Object invoke(Object proxy, Method method, Object[] args)
16             throws Throwable {
17         // TODO Auto-generated method stub
18         DogUtil du = new DogUtil();
19         du.method1();
20         Object result = method.invoke(target, args);
21         du.method2();
22         return result;
23     }
24
25 }

写一个工厂类获取proxy类实例,简化编程

 1 package aop;
 2
 3 import java.lang.reflect.Proxy;
 4
 5 public class MyProxyFactory {
 6     public static Object getProxy(Object target) {
 7         MyInvocationHandler handler = new MyInvocationHandler();
 8         handler.setTarget(target);
 9         return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler);
10     }
11 }

下面是测试类,

 1 package aop;
 2
 3 public class Test {
 4     public static void main(String[] args) {
 5         Dog target = new GunDog();
 6         Dog dog = (Dog)MyProxyFactory.getProxy(target);
 7         dog.info();
 8         dog.run();
 9     }
10 }

执行结果如下,

1 代理开始。。。
2 我是一只猎狗
3 代理结束。。。
4 代理开始。。。
5 我奔跑迅速
6 代理结束。。。

reference

http://blog.csdn.net/luanlouis/article/details/24589193

时间: 2024-10-13 10:21:58

JAVA基础知识之JVM-——动态代理(AOP)的相关文章

Java基础之反射和动态代理

1,反射是依赖于Class对象,然后根据Class对象,去操作该类的资源的.Class对象是发射的基石! 问题1:人这类事物用什么表示?汽车这类事物用什么表示>计算机文件用什么表示?有如此多的事物该用什么表示? 答案:Person类,Car类,File类,这么多的类也是一类事物,这类事物用Class表示. 问题2:Person类的对象,我们知道代表一个具体的人.那么Class类的对象,又代表什么? 一个类,在硬盘上表示一个.class文件,JVM启动的时候,把文件加载到内存上,占用一片空间,称为

java基础知识之JVM

JVM是运行java字节码的虚拟机,包括一套字节码指令集.一组寄存器.一个栈.一个垃圾回收,堆和一个存储方法域.运行: java源文件-->编译器-->字节码文件 字节码文件-->JVM-->机器码 ,当一个程序从开始运行,这时虚拟机就开始实例化了,多个程序启动就会存在多个虚拟机实例.程序退出或者关闭,则虚拟机实例消亡,多个虚拟机实例之间数据不能共享.1.8jdk使用的是Sun公司的HotSpot和BEA公司的JRockit两个精华形成的JVM 1. 类的实例化顺序,比如父类静态数

学习Spring必学的Java基础知识(2)----动态代理

学习Spring必学的Java基础知识(2)----动态代理 引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓“登高必自卑,涉远必自迩”.以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系列分别介绍这些Java基础知识,希望对大家有所帮助.): [1] Java反射知识-->Spring IoC :http://www.iteye.com/topic/1123081 [2] Java动态代理-->Spring AOP :http://www

学习Spring必学的Java基础知识(1)----反射

引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓“登高必自卑,涉远必自迩”.以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系列分别介绍这些Java基础知识,希望对大家有所帮助.): [1] Java反射知识-->Spring IoC :http://www.iteye.com/topic/1123081 [2] Java动态代理-->Spring AOP :http://www.iteye.com/topic/1123293 [3] 属性

学习Spring必学的Java基础知识(1)----反射(转)

引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓"登高必自卑,涉远必自迩".以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系列分别介绍这些Java基础知识,希望对大家有所帮助.): [1] Java反射知识-->Spring IoC :http://www.iteye.com/topic/1123081 [2] Java动态代理-->Spring AOP :http://www.iteye.com/topic/1123

主题:学习Spring必学的Java基础知识(8)----国际化信息

引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓"登高必自卑,涉远必自迩".以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系列分别介绍这些Java基础知识,希望对大家有所帮助.):[1] Java反射知识-->Spring IoC :http://www.iteye.com/topic/1123081[2] Java动态代理-->Spring AOP :http://www.iteye.com/topic/112329

沉淀,再出发:Java基础知识汇总

沉淀,再出发:Java基础知识汇总 一.前言 不管走得多远,基础知识是最重要的,这些知识就是建造一座座高楼大厦的基石和钢筋水泥.对于Java这门包含了编程方方面面的语言,有着太多的基础知识了,从最初的语法,对象的定义,类.接口.继承.静态.动态.重载.覆盖这些基本的概念和使用方法,到稍微高级一点的多线程,文件读写,网络编程,GUI使用,再到之后的反射机制.序列化.与数据库的结合等高级一点的用法,最后将设计模式应用其中,产生了一个个新的概念,比如Spring.Spring MVC.Hibernat

学习Spring必学的Java基础知识(7)----事务基础知识

引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓“登高必自卑,涉远必自迩”.以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系列分别介绍这些Java基础知识,希望对大家有所帮助.): [1] Java反射知识-->Spring IoC :http://www.iteye.com/topic/1123081 [2] Java动态代理-->Spring AOP :http://www.iteye.com/topic/1123293 [3] 属性

Java基础知识的三十个经典问答

Java基础知识的三十个经典问答 1.面向对象的特点 抽象: 抽象是或略一个主题中与当前目标的无关的因素,一边充分考虑有关的内容.抽象并不能解决目标中所有的问题,只能选择其中的一部分,忽略其他的部分.抽象包含两个方面:一是过程抽象:一是数据抽象. 继承 继承是一种联接类的层次模型,允许和鼓励类的重用,提供了一种明确的共性的方法.对象的一个新类可以从现有的类中派生,这叫做类的继承.心累继承了原始类 的特性,新类称为原始类的派生类或者是子类,原始类称为新类的基类或者父类.子类可以从父类那里继承父类的

Java的反射机制和动态代理

介绍Java注解的时候,多次提到了Java的反射API.与javax.lang.model不同的是,通过反射API可以获取程序在运行时刻的内部结构.反射API中提供的动态代理也是非常强大的功能,可以原生实现AOP中 的方法拦截功能.正如英文单词reflection的含义一样,使用反射API的时候就好像在看一个Java类在水中的倒影一样.知道了Java类的内部 结构之后,就可以与它进行交互,包括创建新的对象和调用对象中的方法等.这种交互方式与直接在源代码中使用的效果是相同的,但是又额外提供了运行时