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

2014-11-23 21:50:19 · 作者: · 浏览: 63
).getClassLoader(), obj .getClass().getInterfaces(), new CommonProxy(obj)); 通过Proxy.newProxyInstance函数来创建代理对象,我们看看这个函数的声明(去掉了一些相关说明):

    /**
     * Returns an instance of a proxy class for the specified interfaces
     * that dispatches method invocations to the specified invocation
     * handler.  This method is equivalent to:
     *
     * @param   loader the class loader to define the proxy class
     * @param   interfaces the list of interfaces for the proxy class
     *          to implement
     * @param   h the invocation handler to dispatch method invocations to
     * @return  a proxy instance with the specified invocation handler of a
     *          proxy class that is defined by the specified class loader
     *          and that implements the specified interfaces
     */
    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class
  [] interfaces,
                                          InvocationHandler h)

可以看到,第一个参数是被代理对象的ClassLoader, 参数2是被代理对象所有接口列表的Class数组,参数三为InvocationHandler对象,就是实现了InvocationHandler接口的类,对应上面的CommonProxy类型。看我们的实现 :

	public static 
  
    T createProxy(T obj) {

		return (T) Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
				.getClass().getInterfaces(), new CommonProxy(obj));

	}
  
被代理对象obj通过参数传递进来,我们通过obj.getClass().getClassLoader()获取ClassLoader对象,然后通过obj.getClass().getInterfaces()获取它实现的所有接口,然后将obj包装到实现了InvocationHandler接口的CommonProxy对象中。通过newProxyInstance函数我们就获得了一个动态代理对象。

下面看看这个动态代理类的使用:

	public static void main(String[] args) {
		// 获得对象
		Socialize mController = CommonProxy
				.createProxy(new SocializeImpl());
		// 调用方法
		mController.doAothorize();
		mController.share();

		// 获取动态代理对象,然后输出调用历史记录
		CommonProxy proxy = (CommonProxy) Proxy
				.getInvocationHandler(mController);
		for (Method md : proxy.getHistories()) {
			System.out.println("调用了: " + md.getName());
		}
		
		// 通用的动态代理类, 返回的是接口类型
		Network network = CommonProxy.createProxy(new CommonNetwork());
		network.surfTheInternet();
	}
输出 :

** 执行doAothorize函数之前, 记录到日志系统 **
doAothorize
** 执行share函数之前, 记录到日志系统 **
share
调用了: doAothorize
调用了: share
** 执行surfTheInternet函数之前, 记录到日志系统 **
直接上网,随便看点什么...

可以看到,我们可以通过CommonProxy代理不同类型的对象,如果我们把对外的接口都通过动态代理来实现,那么所有的函数调用最终都会经过invoke函数的转发,因此我们就可以在这里做一些操作,比如日志系统、事务、拦截器、权限控制等。这也就是AOP(面向切面编程)的基本原理吧。

动态代理原理剖析

下面我们来简单的分析一下动态代理的实现原理,主要的类是Proxy以及它的newProxyInstance函数。其实动态代理的原理大致是这样的,获取被代理对象的所有接口,因此可以通过反射获取到被代理对象所有的函数。JVM内部会构建一个继承自Proxy类,且实现了被代理对象所有接口的$Proxy+数字(例如$Proxy1)的类,这些工作都是通过Proxy.newProxyInstance函数实现,并且返回该$ProxyX类的对象。调用$ProxyX类对象的相关函数时,它会将其转发到InvocationHandler实现类中的invoke函数,因此我们可以在此进行其他额外的操作。下面,我们给main函数加上一些代码,如下 :
	public static void main(String[] args) {
		
		// 通用的动态代理类, 返回的是接口类型
		Network network = CommonProxy.createProxy(new CommonNetwork());
		network.surfTheInternet();
		
		// 输出network对象的类名
		System.out.println(network.getClass().getName());
		// 输出network所属类的所有函数
		for (Method md : network.getClass().getDeclaredMethods()) {
			System.out.println("函数 : " + md.getName());
		}
		
		// 输出network所属类的所有函数
		for (Class
   cls : network.getClass().getInterfaces()) {
			System.out.println("实现的接口 : " + cls.getName());
		}
		
		// 输出network所属类的父类
		System.out.println(network.getClass().getGenericSuperclass());
		
	}
输出 :
直接上网,随便看点什么...
com.thingking.in.java.proxy.$Proxy1
函数 : equals
函数 : toString
函数 : hashC