Java中的静态代理、通用动态代理类以及原理剖析(一)

2014-11-23 21:50:19 · 作者: · 浏览: 62

代理模式和静态代理

在开发中,代理模式是常用的模式之一,一般来说我们使用的代理模式基本上都是静态代理,实现模式大致如下 :

\

我们以网络代理为例,简单演示一下静态代理的实现 :

// 网络接口
interface Network {
	public void surfTheInternet();

	public void gotoFacebook();
}

// 普通网络
class CommonNetwork implements Network {

	@Override
	public void surfTheInternet() {
		System.out.println("直接上网,随便看点什么...");
	}

	@Override
	public void gotoFacebook() {
		System.out.println("上facebook,被墙了,没法弄啊!!!");
	}

}

// 网络代理
class NetworkProxy implements Network {
	@Override
	public void surfTheInternet() {
		System.out.println("代理上网");
	}

	@Override
	public void gotoFacebook() {
		System.out.println("上facebook, 即使被墙了,使用网络代理也能上!!!");
	}
}
main函数 :

	public static void main(String[] args) {
		Network myNetwork = new CommonNetwork();
		myNetwork.surfTheInternet();
		myNetwork.gotoFacebook();
		
		myNetwork = new NetworkProxy() ;
		myNetwork.gotoFacebook();
	}
输出 :

直接上网,随便看点什么...
上facebook,被墙了,没法弄啊!!!
上facebook, 即使被墙了,使用网络代理也能上!!!
总之,代理对象就是把被代理对象包装一层,在其内部做一些额外的工作,比如用户需要上facebook, 而普通网络无法直接访问,网络代理帮助用户先翻墙,然后再访问facebook。这就是代理的作用了。

动态代理

上面的网络代理示例中,一个代理只能代理一种类型,而且是在编译器就已经确定被代理的对象。而动态代理是在运行时,通过反射机制实现动态代理,并且能够代理各种类型的对象。JDK 5中引入的动态代理机制,允许开发人员在运行时刻动态的创建出代理类及其对象。在运行时刻,可以动态创建出一个实现了多个接口的代理类。每个代理类的对象都会关联一个表示内部处理逻辑的InvocationHandler接 口的实现。当使用者调用了代理对象所代理的接口中的方法的时候,这个调用的信息会被传递给InvocationHandler的invoke方法。在 invoke方法的参数中可以获取到代理对象、方法对应的Method对象和调用的实际参数。invoke方法的返回值被返回给使用者,这种做法实际上相当于对方法调用进行了拦截,这样我们就可以在调用invoke的前后做自己想做的事。熟悉AOP的人对这种使用模式应该不陌生。但是这种方式不需要依赖AspectJ等AOP框架。下面我们看一个示例 :

新增一个被代理类 :

/**
 * 社会化组件, 带有授权、分享功能
 * @author mrsimple
 *
 */
public interface Socialize {
	// 授权
	public void doAothorize();
	// 分享
	public void share();
}

public class SocializeImpl implements Socialize {

	@Override
	public void doAothorize() {
		System.out.println("doAothorize");
	}

	@Override
	public void share() {
		System.out.println("share");
	}

}

通用动态代理类:

/**
 * 动态代理通用类, 实现InvocationHandler接口。
 * 
 * @author mrsimple
 *
 */
public class CommonProxy implements InvocationHandler {

	/**
	 * 目标对象
	 */
	private Object mTarget;

	/**
	 * 方法调用日志
	 */
	private List
  
    mHistories = new ArrayList
   
    (); /** * 注入被代理的对象 * @param obj */ private CommonProxy(Object obj) { mTarget = obj; } /** * 执行真正代码之前做的事 * @param md * @param args */ private void before(Method md, Object[] args) { System.out.println("** 执行" + md.getName() + "函数之前, 记录到日志系统 **"); } /* * 调用任何函数都会以invoke函数为入口, proxy参数是被代理的真实对象,method为被调用的函数,arg为参数 */ @Override public Object invoke(Object proxy, Method method, Object[] args) { // before before(method, args); // 将调用记录保存起来 mHistories.add(method); try { // 执行真正的函数调用 return method.invoke(mTarget, args); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return null; } /** * 通过代理创建对象, 返回的必须是接口类型 * * @param obj * 目标接口类型 * @return */ @SuppressWarnings("unchecked") public static 
    
      T createProxy(T obj) { return (T) Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj .getClass().getInterfaces(), new CommonProxy(obj)); } /** * * @return */ public List
     
       getHistories() { return mHistories; } }
     
    
   
  
上面就是一个通用的动态代理类。创建代理对象的工厂方法createProxy中的Proxy类是至关重要的,参数也有点不好理解,我们来分析一下。

Proxy.newProxyInstance(obj.getClass(