Java动态代理解析

首先简单介绍代理模式,接着详解Java中动态代理的使用并分析其运行过程。

代理模式具体理论可以参照设计模式类书籍等。简单假定为请求者向某个实体请求方法,在实现上可以分以下两种类别:一是代理类中拥有实体的对象,方法中通过该对象返回请求想要的结果;二是代理类继承实体类的接口,进而去实现实体类的接口,同时也需要拥有实体类对象,在接口实现中仍然是调用实体类对象的方法。

第二种实现在设计模式的书上一般被普遍认为是代理模式的原型,这种实现更为规范,易于扩展。下面给出结构图:



在Proxy类中拥有RealSubject的对象,故在Proxy中的Request方法中调用RealSubject的Request方法即可。

下面介绍Java中动态代理的使用。

Java中动态代理和上图类似,拥有proxy的自动实现,即能够去自动调用RealSubject的Request方法,并提供了接口,让我们通过实现该接口,去增强Request方法。例如增加Request方法调用前和调用后的操作。这个特点的优势非常明显,可以在不改变Request方法具体内容的情况下补充代码。这种实现符合代码的封闭开放原则,在很多地方得到应用,如Spring中的AOP,明显的减少了不愿写在一起的代码的耦合度。

Java中需先定义实体类的接口,并用类实现接口。相当于上图中的Subject和RealSubject。Java动态代理中提供了接口InvocationHandler,我们需要将代理方法的增强放入这个接口实现类的invoke方法中。随后我们并不需要实现Proxy的相关内容,仅需要直接调用Proxy类中的newProxyInstance方法即可创建代理的对象。接着就可以使用该对象调用方法。下面给出非常简单的代码实现,仅用于快速理解:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class app {
	
	public static void main(String[] args) {
		RealSubject realSubject = new RealSubject();
		ClassLoader load = realSubject.getClass().getClassLoader();
		Class<?>[] interfaces = realSubject.getClass().getInterfaces();
		HandlerImpl handler = new HandlerImpl(realSubject);	
		Object proxy = Proxy.newProxyInstance(load, interfaces, handler);
		Subject s = (Subject)proxy;
		s.Request();
	}

}

interface Subject {
	void Request();
}

class RealSubject implements Subject {

	@Override
	public void Request() {
		// TODO Auto-generated method stub
		System.out.println("This is RealSubject's Request()");
	}

}

class HandlerImpl implements InvocationHandler{

	private Object realSubject;
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("before");
		method.invoke(realSubject, args);
		System.out.println("after");
		return null;
	}

	public HandlerImpl(Object realSubject){
		this.realSubject = realSubject;
	}
}

上述程序的运行结果是:

before
This is RealSubject's Request()
after

通过在类HandlerImpl 中invoke的实现,我们将增强的代码放入before和after处即可完成我们的目的。


通过以上的简单实现我们可以看出Java动态代理屏蔽了Proxy的实现,通过method.invoke(realSubject, args)这句调用我们基本可以看出动态代理的实现并不复杂,传入的Method即为RealSubject中的Requset方法。下面我们介绍下运行的原理。
首先给出HandlerImpl 和Proxy的结构图:



InvocationHandler接口和Proxy的代码我们可以直接从源代码中看到,唯一对我们屏蔽的即位ProxySubject实现类。可以通过反编译class文件查看其内容。
在我们的代码中,经历了以下几个过程:
(1)HandlerImpl handler = new HandlerImpl(realSubject); 易于理解,创建了handler,并将HanderImpl中的realSubject赋值。
(2)Object proxy = Proxy.newProxyInstance(load, interfacecar, handler); 这里是理解的关键。首先Proxy会给自己的InvocationHandler对象h进行赋值,随后由于传进了interfaces数组。可以直接获取interfaces的名字。由于传进了ClassLoader的对象Load(这里的Load是RealSubject的Load)。故我们可以通过名字从该Load中获取Method对象,即获得Request()方法的对象。
语句很简单,这样写就可以了,method_i = Class.forName("RealSubject").getMethod("Request", loader.loadClass("RealSubject"));这里是自己的理解,动态代理中的具体实现估计大同小异,总之是通过传入的ClassLoader对象和interfaces数组对象获取方法的名字然后获取该方法的对象。
    通过以上操作,我们创建了ProxySubject的类,并拥有了Method对象。即为RealSubject中Request方法的对象。
    (3)s.Request()后; 这里ProxySubject类直接调用h.invoke()即可,对象h是从父类Proxy继承而来,其实从看Proxy源码时h的属性为保护即可看出一定是通过子类的调用实现。传入参数分别为this,method_i,和方法的参数。本例中方法无参数,传入null即可。

通过以上介绍我们大体介绍了Java动态代理的使用和实现机制,后面有机会会尝试自己写一个类去继承Proxy实现类似ProxySubject的功能。下次有机会整理下CGLIB中代理的机制


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值