首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件开发 >

设计形式之动态代理

2012-06-28 
设计模式之动态代理之前写了一篇代理模式的文章,同事介绍了使用代理模式的好处,但是那种代理模式也存在一

设计模式之动态代理
之前写了一篇代理模式的文章,同事介绍了使用代理模式的好处,但是那种代理模式也存在一定的弊端:代理类和被代理类紧紧的耦合在一起了,一个代理类只能为一个代理类服务。这种显然是不愿意看到的,下面用一个例子介绍一下Java的动态代理和深入分析一下Java的动态代理。
被代理对象接口

    if (proxyPkg == null) {
proxyPkg = pkg;
    } else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
    "non-public interfaces from different packages");
    }
}
    }

    if (proxyPkg == null) {// if no non-public proxy interfaces,
proxyPkg = "";// use the unnamed package
    }

    {
/*
* Choose a name for the proxy class to generate.
*/
long num;
synchronized (nextUniqueNumberLock) {
    num = nextUniqueNumber++;
}
String proxyName = proxyPkg + proxyClassNamePrefix + num;
这段逻辑就是产生代理类名称的逻辑,proxyClassNamePrefix是Proxy的一个静待常量
  private final static String proxyClassNamePrefix = "$Proxy";由于此处,我们所有类都在一个package中,所以proxyPkg为空,这又是第一个代理类,所以num为0,所以我们产生这个代理类就就叫做“$Proxy0”。
下面又有一个疑问,既然代理工厂产生的是一个叫做$Proxy0的MyInvokationHander实例,那它为什么又回有GunDog的info()和run()方法呢??
上面已经说了,Proxy 的newProxyInstance方法会要求产生一个实现继承Proxy,实现被代理类实现的所有接口的实例,比如下面:
Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), myHander)
它产生的就是一个myHander实例,该实例继承Proxy,实现了target实现的所有接口(target.getClass().getInterfaces()),而通过DEBUG代码发现,每次执行代dog.info();时,代码都会走到MyInvokationHander.invoke(Object proxy, Method method, Object[] args)方法中。所以我们可以猜测,这个方法Proxy.newProxyInstance其实在内存中产生了这样一个代理类:该代理类有被代理类的所有方法(被代理类肯定已经实现了被代理类实现的接口中的方法),这些方法内部再通过invoke方法调用被代理类的方法(有点绕口)。例如下面就是猜想的,在内存中的代理类:
package com.yf.designpattern.proxy.dynamicproxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class MyInvokationHander implements InvocationHandler {private Object target;public void setTarget(Object target) {this.target = target;}public void info() throws SecurityException, NoSuchMethodException,Throwable {this.invoke(target, this.target.getClass().getDeclaredMethod("info",null), null);}public void run() throws SecurityException, NoSuchMethodException,Throwable {this.invoke(target, this.target.getClass().getDeclaredMethod("run",null), null);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {TxUtil tu = new TxUtil();tu.beginTx();Object result = method.invoke(target, args);tu.endTx();return result;}} 

当然这是本人猜测的一个类,实际在内存中并不一定就是上面这个样子。
从上面可以看出,采用动态代理可以将代理类和进行解耦,代理类已经不再关心被代理类时什么,它只关心需要给被代理的类增强那些功能。
总结:使用动态代理的一般步骤如下:
1、创建代理类,代理类需要实现InvocationHandler接口;
2、创建代理类工厂(也可以不创建),该工厂通过Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException方法创建代理对象(也可以通过Proxy.getProxyClass(loader, interfaces).getConstructor(new Class[] { InvocationHandler.class }).newInstance(new Object[] { handler });)方法创建);
3、将被代理对象传给代理类和代理类工厂即可。
附件中是JDK的部分源码和例子的中源代码

热点排行