Java动态代理总结

动态代理:动态代理本质是一个动态生成增强的被代理对象的过程。

静态代理模式:

(1):首先我们有一个普通的接口和一个实现了这个接口的Class类:


(2):我们创建了一个该类的实例:user Userobject=new userimpl();现在我们希望在执行这个实例中的任何一个方法之前或者之后时都可以自动执行一些额外的代码,比如:记录调用人、验证权限等。


常规做法是利用代理模式,新建一个实现user接口的代理类,传入一个userObject,在代理类的同名方法内调用logout(),如下:

但这样就需要为每个普通类实现一个代理类,如果大量使用会导致类的急剧膨胀。另外在实现代理类时我们需要清楚普通类的构成。因此我们需要动态代理。

动态代理:

首先我们需要清晰我们要解决的问题是什么:我们的目的是对任意一个实现了某个接口(或者某几个)的普通的java类A的任意一个方法a(),当我们调用A.a()时候,系统可以在执行A.a()之前或者之后时自动的完成其他的一些固定的工作:如权限验证,日志记录。并且,这些工作在类A中完全没有代码涉及,即这些工作和类A完全解耦,类A对这些工作毫不知情。

(1)因为类A对这些额外工作毫不知情,所以我们依然需要一个代理类,这个代理类中实现了额外工作的逻辑(权限验证、日志记录等),但是为了改变静态代理模式中需要为每个普通类见一个代理类的情况,我们这个代理类需要能够传入任何类型,所以其构造函数类型为Object。

JDK为我们内置了一个这样的代理接口:InvocationHandler。在java.lang.reflect包下:

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
	throws Throwable;
}
如果要使用动态代理,我们首先必须实现一个继承这个接口的代理类:

public class MyInvocationHandler implements InvocationHandler {
	
	private Object A;
	
	public MyInvocationHandler(Object A) {
		this.A=A;
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
	{
	 // 在目标对象的方法执行之前处理工作  
      System.out.println("------------------before------------------");  
      
    // 执行目标对象的方法  
       Object result = null;
	result = method.invoke(A, args);  	 
    // 在目标对象的方法执行之后处理工作  
    System.out.println("-------------------after------------------");
	return result;  
	}
}

可见我们可以将任意类型的实例传入这个代理类中,并且必须要传入一个类型的实例。

(2)现在我们已经有了一个代理类的实例MyInvoke,这个代理类实例传入的是一个实现foo接口的类型实例:

Foo foo=new Fooclass();
MyInvocationHandler MyInvoke=new MyInvocationHandler(foo);

这个代理类的invoke()方法中就是其他工作与调用方法的结合,我们可以在这儿写入我们调用方法时需要完成的额外工作,如权限验证、日志记录等

public Object invoke(Object proxy, Method method, Object[] args)
	{
	 // 在目标对象的方法执行之前处理工作  
    System.out.println("------------------before------------------");  
      
    // 执行目标对象的方法  
    Object result = null;
	result = method.invoke(A, args);  
	 
    // 在目标对象的方法执行之后处理工作  
    System.out.println("-------------------after------------------");
	return result;  
	}

但是目前为止我们看到没有任何入口调用这个invoke(Objectproxy, Method method, Object[] args)方法。并且我们也不可能主动的调用invoke方法。我们再次明确我们的目的是:当我们执行A.a()时,系统自动的执行其他的额外工作,而不需要我们显示的调用额外的方法。因此我们需要的是一个可以调用invoke方法foo类型对象,而不是一个MyInvocationHandler对象。所以我们需要根据这个代理类对象动态生成一个可以调用invoke方法并且是隐式调用的foo类型的对象。
(3):于是JDK为我们提供了一个根据代理类实例和传入类型继承的所有接口来动态生成一个Object对象的类:
public class Proxy implements java.io.Serializable {

public static Class<?>  getProxyClass(ClassLoader loader, Class<?>... interfaces);
public static Object    newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)	
}

重点是两个static方法getProxyClassnewProxyInstance。
newProxyInstance就是根据根据代理类实例和传入类型继承的所有接口来动态生成一个Class对象的方法。核心代码为:
Class cl = getProxyClass(loader, interfaces);
//调用getProxyClass方法,返回一/动态生成的class对象。
	/*
	 * Invoke its constructor with the designated invocation handler.
	 */
	try {
	    Constructor cons = cl.getConstructor(constructorParams);
	    return (Object) cons.newInstance(new Object[] { h });
//返回一个object类型实例,可强制转换为传入的所有接口的任意一个接口类型
	}
而getProxyClass方法则是整个动态代理的核心,核心代码为:
//生成动态对象的字节码流。
byte[] proxyClassFile =	ProxyGenerator.generateProxyClass(
		    proxyName, interfaces);
		try {
//调用本地方法defineClass0()生成class对象。
		    proxyClass = defineClass0(loader, proxyName,
			proxyClassFile, 0, proxyClassFile.length);
		}
所以通过这两个方法就可以生成一个和传入实例继承接口类型相同的动态对象,如下:
//返回一个object对象,可以转换为传入代理类的类型所继承的所有接口中的任意一个。
public Object getProxy() {  
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),   
        		Foo.getClass().getInterfaces(), this); 
//this就是创建的代理类MyInvocationHandler实例。 
} 

测试main函数:
public class Proxy_main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		Foo foo=new Fooclass();
		
		MyInvocationHandler MyInvoke=new MyInvocationHandler(foo);
		
		Foo fooclass=(Foo)MyInvoke.getProxy();
		
		fooclass.printMessage("poxy");
	}

}

输出如下:

------------------before------------------

This is Object FooClass~!poxy

-------------------after------------------

 

可见此时我们实现了目的:在调用fooclass.printMessage("poxy")时,系统自动执行了其他额外工作。且该中实现方式中实现了代理类和普通类型的完全解耦。普通类只需完成自己的逻辑。额外工作完全在代理类中的invoke()方法中实现,且只需实现一次即可。


现在我们总结一下使用动态代理的步骤:
(1)实现一个继承了InvocationHandler接口的MyInvocationHandler类,在重写的invoke()方法中实现额外工作的逻辑。
(2)通过A.getClass().getInterfaces()得到要代理的类的接口集合。
(3)调用Object Proxy_object=Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), A.getClass().getInterfaces(),MyInvocationHandler);得到一个可以强制转换为(2)步骤中接口集合中任一接口的object对象。
(4)Foo Proxy_Foo=(Foo)Proxy_object;得到动态生成的增强的Foo类型的对象。
(5)正常调用Foo类型方法即可。动态代理已实现。























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值