从原理出发理解JDK动态代理
2014-04-08 00:01
253 查看
一、从静态代理出发
要理解动态代理的原理,首先我们来分析一下静态代理的两种实现方法:
比如说,我有一个Tank类和一个Moveable接口,接口中有一个move的方法,而Tank类实现了这一接口,当我们在交付了代码之后,即原来的代码不能修改了,我们想要在Tank类的那个move()方法中添加日志的逻辑或者时间的计算等等业务逻辑时,我们怎么办?
两种方式:
(1)使用继承的方式实现静态代理;
在这种方式下,我们可以写一个类Tank2,这个类继承Tank类,然后重写move()方法。
增加业务逻辑。
(2)使用聚合的方式实现静态代理;
在这种方式下,我们可以写一个类TankProxy,这个类实现了Moveable接口,然后聚合了Tank作为成员变量,最后实现方法 move(),在其中增加需要的业务逻辑。
那么在静态代理的设计模式中,使用聚合实现还是继承实现会比较好?
答案是采用聚合的方式实现静态代理比较好,原因很简单,我们设想一下,如果我们首先需要添加日志的业务逻辑,这个时候我们采用继承的方式来实现,我们需要建一个新的类Tank1,然后又来了一个业务逻辑,比如效率检查,我们又建一个类Tank2,而当我们需要将各个业务逻辑进行不知道顺序的组合时,每一次我们都要建一个新的类,是不是相当麻烦。我们再看看采用聚合的方式,虽然说每来一个业务逻辑,同样需要建一个类,但当我们需要将业务逻辑不明顺序的组合时,我们不需要建新的类,只需要在客户类中进行设置就可以了;而且我们在设计模式中提到过的面向对象设计原则中,合成复用原则就是提倡我们多用关联,少用继承。(虽然说有点难理解,但是仔细去琢磨,道理就是这样)
二、从原理进入JDK动态代理
首先,我们需要明白为什么会有动态代理,因为静态代理太死了,我们需要对每一个需要代理的目标编写代理类,而动态代理的Proxy可以对任意对象产生代理(不用看到代理类的名字)。
关于JDK动态代理,最最主要和核心的是java.lang.reflect.Proxy这个类和InvocationHandler这个接口。
Proxy类中核心的方法是:
InvocationHandler的核心方法是:
好了,谈完了JDK动态代理的核心之后,我们来分析动态代理的原理:
(1)首先,我们创建一个Proxy类,用这个类来模拟JDK的Proxy类;
编写其最核心的方法,即产生代理类的方法,其中两个参数,一个传递被代理对象所实现的接口,一个是InvocationHandler对象;
在这个方法中我们主要有以下四个步骤来产生代理类:
1.第一步,我们需要动态的将代理类的内容写入一个指定目录下的文件名为$Proxy1(JDK动态代理生成的代理类名字就是这种形式):
生成文件:
2.第二步,将该代理类文件进行编译,生成.class文件:
生成目录:
3.第三步,将类加载到内存中,这里采用URLClassLoader,实际中我们也可以采用从客户端传过来的与被代理类相对应的ClassLoader:
4.第四步,创建代理对象的实例,学过Java反射原理的应该知道,如果一个类没有无参构造函数,那么不能调用newInstance()方法来实现创建实例;而我么所讲的例子中的代理类中是有参构造函数,看看生成的代理文件吧:
从而采用构造器来生成实例:
这就是我们Proxy类中实际会进行的这些操作。
(2)而关于InvocationHandler类,我们只有一个方法:
我们需要任何的业务逻辑,我们都将创建一个类并实现InvocationHandler;例如一个TimeHandler:
(3)客户端:
总而言之,我们首先通过Proxy类产生代理对象,在客户端获得代理对象之后,调用代理后的方法,而在这个方法中我们将会调用InvocationHandler对象的invoke()方法,从而实现业务的添加,即代理。
要理解动态代理的原理,首先我们来分析一下静态代理的两种实现方法:
比如说,我有一个Tank类和一个Moveable接口,接口中有一个move的方法,而Tank类实现了这一接口,当我们在交付了代码之后,即原来的代码不能修改了,我们想要在Tank类的那个move()方法中添加日志的逻辑或者时间的计算等等业务逻辑时,我们怎么办?
两种方式:
(1)使用继承的方式实现静态代理;
在这种方式下,我们可以写一个类Tank2,这个类继承Tank类,然后重写move()方法。
增加业务逻辑。
(2)使用聚合的方式实现静态代理;
在这种方式下,我们可以写一个类TankProxy,这个类实现了Moveable接口,然后聚合了Tank作为成员变量,最后实现方法 move(),在其中增加需要的业务逻辑。
那么在静态代理的设计模式中,使用聚合实现还是继承实现会比较好?
答案是采用聚合的方式实现静态代理比较好,原因很简单,我们设想一下,如果我们首先需要添加日志的业务逻辑,这个时候我们采用继承的方式来实现,我们需要建一个新的类Tank1,然后又来了一个业务逻辑,比如效率检查,我们又建一个类Tank2,而当我们需要将各个业务逻辑进行不知道顺序的组合时,每一次我们都要建一个新的类,是不是相当麻烦。我们再看看采用聚合的方式,虽然说每来一个业务逻辑,同样需要建一个类,但当我们需要将业务逻辑不明顺序的组合时,我们不需要建新的类,只需要在客户类中进行设置就可以了;而且我们在设计模式中提到过的面向对象设计原则中,合成复用原则就是提倡我们多用关联,少用继承。(虽然说有点难理解,但是仔细去琢磨,道理就是这样)
二、从原理进入JDK动态代理
首先,我们需要明白为什么会有动态代理,因为静态代理太死了,我们需要对每一个需要代理的目标编写代理类,而动态代理的Proxy可以对任意对象产生代理(不用看到代理类的名字)。
关于JDK动态代理,最最主要和核心的是java.lang.reflect.Proxy这个类和InvocationHandler这个接口。
Proxy类中核心的方法是:
InvocationHandler的核心方法是:
好了,谈完了JDK动态代理的核心之后,我们来分析动态代理的原理:
(1)首先,我们创建一个Proxy类,用这个类来模拟JDK的Proxy类;
编写其最核心的方法,即产生代理类的方法,其中两个参数,一个传递被代理对象所实现的接口,一个是InvocationHandler对象;
在这个方法中我们主要有以下四个步骤来产生代理类:
1.第一步,我们需要动态的将代理类的内容写入一个指定目录下的文件名为$Proxy1(JDK动态代理生成的代理类名字就是这种形式):
生成文件:
2.第二步,将该代理类文件进行编译,生成.class文件:
生成目录:
3.第三步,将类加载到内存中,这里采用URLClassLoader,实际中我们也可以采用从客户端传过来的与被代理类相对应的ClassLoader:
4.第四步,创建代理对象的实例,学过Java反射原理的应该知道,如果一个类没有无参构造函数,那么不能调用newInstance()方法来实现创建实例;而我么所讲的例子中的代理类中是有参构造函数,看看生成的代理文件吧:
从而采用构造器来生成实例:
这就是我们Proxy类中实际会进行的这些操作。
(2)而关于InvocationHandler类,我们只有一个方法:
我们需要任何的业务逻辑,我们都将创建一个类并实现InvocationHandler;例如一个TimeHandler:
(3)客户端:
总而言之,我们首先通过Proxy类产生代理对象,在客户端获得代理对象之后,调用代理后的方法,而在这个方法中我们将会调用InvocationHandler对象的invoke()方法,从而实现业务的添加,即代理。
相关文章推荐
- JDK 动态代理实现原理
- AOP思想个人理解以及实战静态代理、JDK动态代理、CGlib动态代理
- JDK 动态代理的简单理解
- JDK动态代理实现原理
- jdk动态代理实现原理
- jdk动态代理的实现原理(参考其他文章)
- JDK动态代理的实现及原理
- jdk动态代理和cglib代理的理解
- JDK动态代理实现原理
- jdk动态代理实现原理
- 动态代理(JDK)实现原理
- JDK动态代理干了什么事情?为什么我的事务会不起效?spring的事务到底应该怎么使用?原理是什么?
- JDK动态代理实现原理
- JDK动态代理实现原理
- 深入理解JDK动态代理机制
- jdk 动态代理的原理
- Java JDK 动态代理(AOP)使用及实现原理分析
- JDK动态代理实现原理
- Java动态代理机制原理详解(JDK 和CGLIB,Javassist,ASM)
- 设计模式--JDK动态代理的实现与原理解析(1)