代理技术



什么代理?

一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码。

 

优点

如果采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序,在配置文件中配置是使用目标类、还是代理类,这样以后很容易切换,譬如,想要日志功能时就配置代理类,否则配置目标类,这样,增加系统功能很容易,以后运行一段时间后,又想去掉系统功能也很容易。

 

AOP
系统中存在交叉业务,一个交叉业务就是要切入到系统中的一个方面,如下所示:
                              安全       事务         日志
StudentService  ------|----------|------------|-------------
CourseService   ------|----------|------------|-------------
MiscService       ------|----------|------------|-------------
用具体的程序代码描述交叉业务:
method1         method2          method3
{                      {                       {
------------------------------------------------------切面
....            ....              ......
------------------------------------------------------切面
}                       }                       }
交叉业务的编程问题即为面向方面的编程(Aspect oriented program ,简称AOP),AOP的目标就是要使交叉业务模块化。可以采用将切面代码移动到原始方法的周围,这与直接在方法中编写切面代码的运行效果是一样的,如下所示:
------------------------------------------------------切面
func1         func2            func3
{             {                {
....            ....              ......
}             }                }
------------------------------------------------------切面
使用代理技术正好可以解决这种问题,代理是实现AOP功能的核心和关键技术。

 

动态代理的工作原理:

1)Client(客户端)调用代理,代理的构造方法接受一个InvocationHandler,client调用代理的各个方法,代理的各个方法请求转发给刚才通过构造方法传入的handler对象,又把各请求分发给目标的相应的方法。就是将handler封装起来,其中this引用了当前的放(发来什么请求就接受哪个方法)。
猜想分析动态生成的类的内部代码:
1、动态生成的类实现了Collection接口(可以实现若干接口),生成的类有Collection接口中的所有方法和一个如下接受InvocationHandler参数的构造方法。
2、构造方法接受一个InvocationHandler对象,接受对象了要干什么用呢?该方法内部的代码会是怎样的呢?
实现Collection接口的动态类中的各个方法的代码又是怎样的呢?InvocationHandler接口中定义的invoke方法接受的三个参数又是什么意思?图解说明如下:

分析为什么动态类的实例对象的getClass()方法返回了正确结果呢?
为何动态类的实例对象的getClass()方法返回了正确结果,而没调用invoke方法:
因为代理类从Object上继承了许多方法,其中只对三个方法(hashCode、equals和toString)进行开发,委托给handler去自行处理,对于它身上其他方法不会交给代理类去实现,所以对于getClass()方法,还是由Object本身实现的。即proxy3.getClass(),该是什么结果还是什么结果,并不会交给invoke方法处理。

 

例子

 

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;

public class ProxyTest {
	public static void main(String[] args)throws Exception{
		Class ClazzProxy=Proxy.getProxyClass(Collection.class.getClassLoader(),Collection.class);      //获得代理类的字节码
		System.out.println(ClazzProxy);
		Constructor[] cons=ClazzProxy.getConstructors();                                             //获得代理类的构造方法
		StringBuilder sb=new StringBuilder(); 
		for(Constructor con:cons){
			System.out.print(con.getName());
			sb.append('(');
			Class[] cls=con.getParameterTypes();
			for(Class cl:cls){
				sb.append(cl.getName()+',');
			}
			if(cls!=null&&cls.length!=0)
			sb.deleteCharAt(sb.length()-1);
			sb.append(')');
		}
		System.out.println(sb.toString());
		
		
		System.out.println("Method----------------------------------------");

		Method[] meths=ClazzProxy.getMethods();                                                 //获得代理类的成员方法

		for(Method meth:meths){
			StringBuilder sb1=new StringBuilder(); 
			System.out.print(meth.getName());
			sb1.append('(');
			Class[] cls=meth.getParameterTypes();
			for(Class cl:cls){
				sb1.append(cl.getName()+',');
			}
			if(cls!=null&&cls.length!=0)
			sb1.deleteCharAt(sb1.length()-1);
			sb1.append(')');
			System.out.println(sb1.toString());
		}
		
		System.out.println("----------------------------------------------");
		
		Constructor con=ClazzProxy.getConstructor(InvocationHandler.class);     //获得构造方法
		class Ivct implements InvocationHandler{
			public void invoke(){}

			@Override
			public Object invoke(Object arg0, Method arg1, Object[] arg2)
					throws Throwable {
				// TODO Auto-generated method stub
				return null;
			}
		}
		Collection coll=(Collection)con.newInstance(new Ivct());
		
		//coll.size();                                                    //size会调用InvocationHandler的invoke方法,但是上面的invoke方法返回值是null,而
																			//size需要的是一个int类型的返回值,所以会报错
		
		
		
		
		Collection proxy2=(Collection)Proxy.newProxyInstance(
				Collection.class.getClassLoader(),
				new Class[]{Collection.class},
				new InvocationHandler(){

					 ArrayList al=new ArrayList();
					public Object invoke(Object proxy, Method method,
							Object[] args) throws Throwable {
						Object obj=method.invoke(al, args);
						System.out.println(obj+"Test..........");
						return obj;
					}
					
					
				});
		proxy2.add("zs");                                      //每次调用add方法时,add就会调用InvocationHandler的invoke方法
		proxy2.add("ls");
		proxy2.add("ww");
		System.out.println(proxy2);
		System.out.println(proxy2.size());
	}
}

 



posted @ 2014-07-22 16:04  lisisong  阅读(273)  评论(0编辑  收藏  举报