一、动态代理的理解
动态代理的意义在于生成一个占位(又称代理对象),来代理真实对象,从而控制真实对象的访问。
先来谈谈什么是代理模式。
假设这样一个场景:你的公司是一家软件公司,你是一位软件工程师。客户带着需求去找公司显示不会直接和你谈,而是找商务谈,此时客户认为商务代表公司。
显然客户是通过商务区访问软件工程师的,那么商务(代理对象)的意义在于什么呢?
商务可以进行谈判,比如项目启动前的商务谈判,软件的价格,交付,进度的时间节点等,或者项目完成后的商务追讨应收账务等。商务有可能谈判失败,此时商务就会根据公司规则去结束和客户的合作关系,这些都不用工程师来处理。
因此,代理的作用就是,在真实对象访问之前后者之后加入对应的逻辑,或者根据其他规则控制是否使用真实对象,显然在这个例子里商务控制了客户对软件工程师的访问。
经过上面的论述,我们知道上午和软件工程师是代理和被代理的关系。客户经过商务区访问工程师。此时客户就是程序的调用者,商务就是代理对象,工程师就是真实对象。我们需要在调用者调用对象之前产生一个代理对象,而这个代理对象需要和真实对象建立代理关系,所以我们代理必须分为两个步骤:
(1)代理对象和真实对象之间建立代理关系。
(2)实现代理对象的代理逻辑方法。
二、常用的动态代理
在Java中有多种代理技术,比如:JDK、CGLIB、Javassist、ASM,其中最常用代理技术有两种:一种是JDK动态代理,这是JDK自带的功能,另一种是CGLIB,这是第三方提供的技术。目前Spring常用JDK和CGLIb,而MyBatis还使用了Javassist,但是无论哪种技术,它们的理念是相似的。
三、JDK动态代理(测试)
创建一个接口:HelloWorld.java
1 package com.xfwl.proxy;
2
3 public interface HelloWorld {
4 public void sayHelloWorld();
5 }
创建一个实现子类:HelloWorldImpl.java
1 package com.xfwl.proxy;
2
3 public class HelloWorldImpl implements HelloWorld {
4
5 public void sayHelloWorld() {
6 System.out.println("Hello World!");
7 }
8 }
创建一个代理类:JdkProxyExample.java
package com.xfwl.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDK的动态代理
* @function 两个步骤:(1)建立代理对象和真实服务对象的关系。(2)实现代理逻辑。
* @author 小风微凉
* @time 2018-7-9 上午10:45:53
*/
public class JdkProxyExample implements InvocationHandler {
//真实对象
private Object target=null;
/**
* 建立代理对象和真实对象之间的代理关系,并返回代理对象
* @param target 真实对象
* @return 代理对象
*/
public Object bind(Object target){
this.target=target;
return Proxy.newProxyInstance(
target.getClass().getClassLoader(), //类加载器
target.getClass().getInterfaces(), //动态代理所挂的接口
this //实现方法逻辑的代理类,必须实现InvocationHandler接口的invoke方法
);
}
/**
* 代理方法逻辑
* @param proxy 代理对象
* @param method 当前调度方法
* @param args 当前方法参数
* @return 代理结果返回
* @throws Throwable 异常
*/
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
System.out.println("进入代理方法");
System.out.println("在调度真实方法之前的服务");
Object obj=method.invoke(this.target, args);//相当于调用sayHelloWorld方法
System.out.println("在调度真实方法之后的服务");
return obj;
}
}
创建一个测试类:TestProxy.java
1 package com.xfwl.proxy;
2 /**
3 * 测试JDK代理
4 * @function 分析JDK是如何实现代理的
5 * @author 小风微凉
6 * @time 2018-7-9 上午10:47:14
7 */
8 public class TestProxy {
9 /**
10 * 测试入口
11 */
12 public static void main(String[] args) {
13 JdkProxyExample jdk=new JdkProxyExample();
14 //绑定关系,因为挂在接口HelloWorld下,所以生命代理对象HelloWorld proxy
15 HelloWorld proxy=(HelloWorld)jdk.bind(new HelloWorldImpl());
16 //注意,此时HelloWorld对象已经是一个代理对象,它会进入代理的逻辑方法invoke里
17 proxy.sayHelloWorld();
18 }
19 }
测试结果:
进入代理方法
在调度真实方法之前的服务
Hello World!
在调度真实方法之后的服务
四、CGLIB动态代理(测试)
待续。。。。。。。。。。。。。
五、总结一下
待续。。。。。。。。。。。。。