JDK中的Poxy类简单实现动态代理

来源:互联网 发布:南京网络推广江苏斯点 编辑:程序博客网 时间:2024/05/20 16:14

一、类所在位置

Proxy类在java.lang.reflect包下

java.lang.Object  继承者 java.lang.reflect.Proxy
所有已实现的接口:

Serializable


二、该类的主要方法

Object proxyObject = Proxy.newProxyInstance(loader , interfaces, h);

三个参数的意义

1.classLoader 类加载器,将class文件加载到内存中,形成class对象
2.Class[] interfaces 需要实现的接口
3.InvocationHandler 调用处理器,代理对象的所实现的所有接口的方法,内容都是调用InvocationHandler
的invoke()方法

现在写代码测试下这个类,现有接口A,B,动态生成一个类同时实现A和B接口,代码如下
package org.edu.proxy;    import java.lang.reflect.InvocationHandler;  import java.lang.reflect.Method;  import java.lang.reflect.Proxy;    import org.junit.Test;    public class Demo1 {      interface A {          void a();          void aa();      }      interface B {          void b();          void bb();      }      @Test      public void test1() {          /*          * 给出三大参数,然后动态生成这个类,这个类实现了提供的接口,然后生成这个类的对象          * 1.classLoader 类加载器          * 2.Class[] interfaces 需要实现的接口          * 3.InvocationHandler 调用处理器,代理对象的所实现的所有接口的方法,内容都是调用InvocationHandler          * 的invoke()方法          */                    ClassLoader loader = this.getClass().getClassLoader();          Class[] interfaces = {A.class, B.class};          InvocationHandler h = new InvocationHandler() {                            @Override              public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                  // TODO Auto-generated method stub                  System.out.println("你好动态代理");                  return null;              }          };          Object proxyObject = Proxy.newProxyInstance(loader , interfaces, h);          A a = (A) proxyObject;          a.a();          a.aa();          B b = (B) proxyObject;          b.b();          b.bb();      }  }


单元测试结果如下

从结果中可以看出两个问题。
1.将代理对象强转成A接口和B接口没有报错,说明生成的代理对象同时实现了A接口和B接口。
2.调用代理对象的a()方法、aa()方法、b(),还有bb()方法,结果都是调用了InvocationHandler的invoke()方法,说明执行代理的对象的方法都是通过执行InvocationHandler的invoke()方法来实现的。

好,这是我们再测试下是不是所有方法都是这样呢?
结果发现,在执行toStirng()方法的时候执行了invoke()
在执行getClass()方法的时候没有执行,在执行hashcoe()方法的时候抛出了异常,这个不知道为什么。看了Object类的源码,发现getClass()方法是final和native修饰的,说明是本地方法,是用底层的c写的,不涉及到java代码,没有被重写。

我们想知道这个类的类型到底是什么,于是加入
System.out.println(a.getClass().getName());
结果是org.edu.proxy.$Proxy4

说明生成的对象的类型是一个代理类,为什么叫这个名字,who konws!


三、InvocationHandler的invoke()方法

public Object invoke(Object proxy, Method method, Object[] args)

现在解释下这个方法的参数和返回值

Object proxy:代理对象。
Method method:调用的方法
Object[] args:实参,调用接口方法传进来的的参数
Object返回值:接口方法的返回值

四、动态代理的简单实现

动态代理的作用,增强
将原有的对象和需要增强的功能结合成一个代理对象,从而达到增强的效果。
代理对象=目标对象+增强
比如现在我有一个服务员接口,接口有服务方法,一个男服务员继承了这个接口,这个男服务员很呆板,只会服务,现在我需要让他变得礼貌一点,开始说您好,结束时说再见。我该怎么实现呢?

服务员接口
package org.edu.proxy;/** * 服务员类 * @author ZGJ * @date 2016年12月4日 */public interface Waiter {/** * 服务方法 */void serve();}

男服务员类
package org.edu.proxy;/** * 男服务员 * @author ZGJ * @date 2016年12月4日 */public class ManWaiter implements Waiter{@Overridepublic void serve() {// TODO Auto-generated method stubSystem.out.println("服务中......");}}


实现如下
package org.edu.proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import org.junit.Test;/** *  * @author ZGJ * @date 2016年12月4日 */public class Demo2 {@Testpublic void fun() {ManWaiter manWaiter = new ManWaiter();ClassLoader loader = this.getClass().getClassLoader();Class[] interfaces = {Waiter.class};//传入目标对象InvocationHandler h = new WaiterInvocationHandler(manWaiter);//得到增强的代理对象Waiter waiterProxy = (Waiter) Proxy.newProxyInstance(loader , interfaces, h);//开始时说您好,结束时说再见waiterProxy.serve();}}class WaiterInvocationHandler implements InvocationHandler{private Waiter Waiter;public WaiterInvocationHandler(Waiter waiter) {// TODO Auto-generated constructor stubthis.Waiter = waiter;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// TODO Auto-generated method stubSystem.out.println("您好!");Waiter.serve();System.out.println("再见!");return null;}}

在创建InvocationHandler的时候,传入Waiter的对象,在invoke方法中,先执行前置增强,再调用waiter的server()方法,再执行后置增强,从而达到增强的效果。
但是,这种方式好像不是特别灵活,因为增强的方式都写死了,不够灵活。
这个时候,就可以使用代理工厂来实现生产代理对象
1.现在写两个接口
BeforeAdvice 前置增强
package org.edu.proxy.demo3;/** * 前置增强 * @author ZGJ * @date 2016年12月4日 */public interface BeforeAdvice {void before();}

AfterAdvice 前置增强
package org.edu.proxy.demo3;/** * 后置增强 * @author ZGJ * @date 2016年12月4日 */public interface AfterAdvice {void after();}

ProxyFactory代理工厂类
package org.edu.proxy.demo3;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/** * 代理工厂类 * @author ZGJ * @date 2016年12月4日 */public class ProxyFactory {private Object target;//目标对象private BeforeAdvice beforeAdvice;//前置增强private AfterAdvice afterAdvice;//后置增强/** * 用来生成代对象 * @return */public Object createProxy() {ClassLoader loader = this.getClass().getClassLoader();Class<?>[] interfaces = target.getClass().getInterfaces();InvocationHandler h = new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// TODO Auto-generated method stub//执行前置增强if(beforeAdvice != null) {beforeAdvice.before();}//调用目标方法Object result = method.invoke(target, args);//执行后置增强if(afterAdvice != null) {afterAdvice.after();}return result;}};/* * 三大参数 */Object proxyObject = Proxy.newProxyInstance(loader, interfaces, h);return proxyObject;}public Object getTarget() {return target;}public void setTarget(Object target) {this.target = target;}public BeforeAdvice getBeforeAdvice() {return beforeAdvice;}public void setBeforeAdvice(BeforeAdvice beforeAdvice) {this.beforeAdvice = beforeAdvice;}public AfterAdvice getAfterAdvice() {return afterAdvice;}public void setAfterAdvice(AfterAdvice afterAdvice) {this.afterAdvice = afterAdvice;}}

Demo3实现了目标对象和增强都可以切换
package org.edu.proxy.demo3;import org.junit.Test;/** * 目标对象和增强都可以切换的动态代理 * @author ZGJ * @date 2016年12月4日 */public class Demo3 {@Testpublic void fun() {Waiter waiter = new ManWaiter();ProxyFactory factory = new ProxyFactory();//创建工厂factory.setTarget(waiter);//设置目标对象factory.setBeforeAdvice(new BeforeAdvice() {@Overridepublic void before() {// TODO Auto-generated method stubSystem.out.println("您好");}});factory.setAfterAdvice(new AfterAdvice() {@Overridepublic void after() {// TODO Auto-generated method stubSystem.out.println("再见");}});Waiter waiterProxy = (Waiter) factory.createProxy();waiterProxy.serve();}}

如果我想修改前置增强的方法,只需新建一个类继承前置增强的接口就行了,后置增强同理,被增强的目标对象也可以切换,这样就灵活很多了。



1 0
原创粉丝点击