动态代理模式
动态代理的意义在于生成一个占位(又称代理对象),来代理真实对象,从而控制真实对象的访问。
先来谈谈什么是代理模式。假设这样一个场景,你的公司是一家软件公司,你是一位软件工程师。客户带着需求去找公司显然不会直接和你谈,而是去找商务谈,此时客户会认为商务就代表公司。

显然客户是通过商务去访问软件工程师的,那么商务(代理对象)的意义是什么呢?商务可以进行谈判,比如项目启动前的商务谈判,项目的资金,交付,进度等。或者项目完成之后结尾款等。因此,代理的作用就是,在真实对象访问之前或者之后加入对应的逻辑,或者根据其他规则控制是否使用真实对象,显然在这个例子里商务控制了客户对软件工程师的访问。
经过上面的论述。代理可分为两个步骤:
● 代理对象和真实对象建立代理关系。
● 实现代理对象的代理逻辑方法。
在java中有多种动态代理技术。如JDK、CGLIB、javassist、ASM。其中最常用的动态代理技术有两种:一种是JDK动态代理,这是JDK自带的功能;另一种是CGLIB,这是第三方提供的一个技术,目前,spring常用JDK和CGLIB,而MyBatis还使用了Javassist,无论哪种代理其技术,他们的理念都是相似的。下面通过代码讲解一下JDK动态代理技术。
JDK动态代理技术是java.lang.reflect.*包提供的方式,塔必须借助一个接口才能产生代理对象,所以先定义接口,如下:
public interface Helloworld { public void sayHelloword(String a); }
然后提供实现类Helloworld来实现接口,代码如下:
public class HelloworldImpl implements Helloworld{ @Override public void sayHelloword(String a){ System.out.println("hello world"+a); } }
这是最简单的java接口和实现类的关系,此时可以开始动态代理了。按照我们之前的分析,先要建立起代理对象和真实服务对象的关系。然后实现代理逻辑,所以一共分为两个步骤。
在JDK动态代理中,要实现代理逻辑类必须去实现java.lang.reflect.InvocationHandler接口,它里面定义了一个invoke方法,并提供接口数组用于下挂代理对象,代码如下:
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); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{ System.out.println("进入代理逻辑方法"); System.out.println("在调度真实对象之前的服务"); Object obj = method.invoke(target,args);//相当于调用sayhelloworld方法 System.out.println("在调度真实对象之后的服务"); return obj; } }
第一步,建立代理对象和真实对象的关系。这里使用了bind方法去完成的,方法里面首先用类的属性target保存了真实对象,然后通过如下代码建立并生成代理对象。
Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
其中newProxyInstance方法包含3个参数。
● 第一个是类加载器,我们采用了target本身的类加载器。
● 第二个是把生成的动态代理对象下挂在哪些接口下,这个写法就是放在target实现的接口下。HelloWorldImpl对象的接口显然就是HelloWorld,代理对象可以这样生命:HelloWorld proxy = xxxxx;
● 第三个是定义实现方法逻辑的代理类,this表示当前对象,他必须实现InvocationHandler接口的Invoke方法,他就是代理逻辑方法的实现方法。
第二步,实现代理逻辑方法。invoke方法可以实现代理逻辑,invoke方法的3个参数的含义如下:
● proxy,代理对象,就是bind方法生成的对象
● method,当前调度的方法
● args,调度方法的参数。
当我们使用了代理对象调度之后,他就会进入到invoke方法里。
Object obj = method.invoke(target,args);
这行代码相当于调度真实对象的方法,只是通过反射实现而已。
类比前面的例子,proxy相当于商务对象,target相当于软件工程师对象,bind方法就是建立商务和软件工程师代理关系的方法。而invoke就是商务逻辑,他将控制软件工程师的访问。
测试JDK动态代理,代码如下:
public static void main(String[] args) { Helloword proxy = (Helloword) lanjieqi_InterceptorJdkProxy.bind(new HelloworldImpl(), "main.java.dongtaidaili.lanjieqi_MyInterceptor"); proxy.sayHelloword("hongwei"); }
反射方法前逻辑
hello worldhongwei
反射方法后逻辑
此时,在调度打印hello world之前和之后都可以加入相关的逻辑,甚至可以不调度hello world的打印。
这就是JDK动态代理,它是一种最常用的动态代理。

浙公网安备 33010602011771号