黑马程序员15_代理类

代理类

知识点一:代理类概述

编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码。而要为系统中的各种接口的类增加代理功能,那将需要太多的代理类,全部采用静态代理方式,将是一件非常麻烦的事情。JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。


 

知识点二:创建动态代理类

jvm创建动态类及其实例对象需要三个方面:

1、生成的类中有哪些方法,通过让其实现哪些接口的方式进行告知;

2、产生的类字节码必须有个一个关联的类加载器对象;

3、生成的类中的方法的代码是怎样的,也得由我们提供。把我们的代码写在一个约定好了接口对象的方法中,把对象传给它,它调用我的方法,即相当于插入了我的代码。提供执行代码的对象就是那个InvocationHandler对象,它是在创建动态类的实例对象的构造方法时传递进去的。在上面的InvocationHandler对象的invoke方法中加一点代码,就可以看到这些代码被调用运行了。

  •  方式1:

 思想:通过Proxy类的构造函数传入InvocationHandler的一个对象获得

 步骤:

 1、通过getProxyClass得到Preoxy类的字节码

 2、由Preoxy_code得到 参数类型为InvocationHandler的构造函数

 3、构造实现了InvocationHandler接口的类,从而new出一个InvocationHandler对象handler

 4、通过得到的参数类型为InvocationHandler的构造函数,传入handler,得到一个Proxy实例

代码如下:

 

import java.lang.reflect.*;
import java.util.Collection;
public class ProTest 
{
	public static void main(String[] args)throws Exception {
		Class clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);//得到Preoxy_code
	  
Constructor constructor = clazzProxy.getConstructor(InvocationHandler.class);
//由Preoxy_code得到 参数类型为InvocationHandler的构造函数
class myInvocationHander implements InvocationHandler		
//构造实现了InvocationHandler接口的类
{
  public Object invoke(Object arg0, Method arg1, Object[] arg2)  
  //返回对象Object
					throws Throwable {
								return null;
			}
	    }
	    Collection proxy1 = (Collection) constructor.newInstance(new myInvocationHander()); 
 //new出一个proxy实例
	    System.out.println(proxy1.toString());
	}
}
  •  方式2:

 思想:通过Proxy类的构造函数传入InvocationHandler的一个对象获得,该对象由    内部类获得

 步骤:

 1、通过getProxyClass得到Preoxy类的字节码

 2、由Preoxy_code得到 参数类型为InvocationHandler的构造函数

 3、通过得到的参数类型为InvocationHandler的构造函数,传入由内部类new出的handler,得到一个Proxy实例

代码如下:

 

import java.lang.reflect.*;
import java.util.Collection;
public class ProTest {
	public static void main(String[] args)throws Exception 
	{
		Class clazzProxy = 
			Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);//得到Preoxy_code
	    Constructor constructor = 
	    	clazzProxy.getConstructor(InvocationHandler.class);
  //由Preoxy_code得到 参数类型为InvocationHandler的构造函数
	    
	    Collection proxy1 = 
	    	(Collection) constructor.newInstance(new InvocationHandler() 
  //使用内部类new出一个Proxy类实例
	    	{
	    	public Object invoke(Object arg0, Method arg1, Object[] arg2) 
			throws Throwable {
		return null;
	}
	    	}); 
	    System.out.println(proxy1.toString());
	}
}

 

  • 方式3:

思想:用newPorxyInstance方法直接创建

Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),                                              new Class[] { Foo.class },                                               handler);

陈潞的理解:3个参数的意思

Foo.class.getClassLoader()//做事的保证体系

new Class[] { Foo.class }//要做的事,即目标对象的方法,代理类要实现的接口列表

Handler//代理类对象实例,由做事的人实现代理功能(即实际做事的类实现接口InvocationHandler的invoke方法),可用内部类实现即:new InvocationHandler(做事的人){targe.invoke(对象,参数)}

实例代码如下:

 

Collection proxy = (Collection)Proxy.newProxyInstance
                                                     (
  Collection.class.getClassLoader(),
	    					new Class[] { Collection.class },
	    					new InvocationHandler() 	   
{
public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable
  {									    							return null;
	    }
}

  

 


 

知识点三:用代理类的对象执行目标对象

思想:

InvocationHandler对象中存放目标对象(可通过创建方式获得),然后在执行该目标对象相应方法的前后家上必要的操作。

步骤:

1、在InvocationHandler方法中创建目标对象

2、实现(必须)InvocationHandler接口的invoke(Object arg0, Method  method方法, Object[] arrgs参数)方法,将相应参数传递给目标对象(包括目标对象的方法method以及方法的参数arrgs)。

3、对象通过反射机制通过对象.invoke方法执行目标对象的相应方法。

代码如下:

 

Collection proxy = (Collection)Proxy.newProxyInstance(
Collection.class.getClassLoader(),
new Class[] { Collection.class },
new InvocationHandler() //使用内部类new出一个Proxy类实例
{	
  //1、在InvocationHandler方法中创建目标对象
	ArrayList target = new ArrayList();
  //2、实现(必须)InvocationHandler接口的invoke(Object arg0, Method  method方法, Object[] arrgs参数)方法,将相应参数传递给目标对象(包括目标对象的方法method以及方法的参数arrgs)。
	 public Object invoke(Object proxy, Method method, Object[] arg2) 
	 throws Throwable
	 {		
            //方法执行之前可进行所需操作
  Long beginTime = System.currentTimeMillis();
  //3、对象通过反射机制通过对象.invoke方法执行目标对象的相应方法。
   			Object result = method.invoke(target,arg2);
	    	//方法执行之后可进行所需操作
  Long endTime = System.currentTimeMillis();			    	System.out.println(beingTime-endTime);
  //将运行的结果返回
	        return result;
	    }
  }

  

 


 

知识点四:用代理类来执行目标函数

思想:其实是在InvocationHandler接口中通过目标对象反射机制完成。

如:

proxy.add(“java1”);//返回true

运行过程分析:

Proxy.add(“java1”)对应了public Object invoke(Object proxy, Method method, Object[] args)中的三个参数。 method---add args---”java1”。

这个方法的返回值是object,也就是invoke方法中的reult

 

  • 练习:

模拟代理类

import java.lang.reflect.*;
import java.util.Collection;
public class Client {

	public static void main(String[] args) {
		DoBussiness target = new DoBussiness();
		BussinessHandler handler = new BussinessHandler(target);
		//newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序
		Bussinessy interfaces = (Bussinessy)Proxy.newProxyInstance(
															target.getClass().getClassLoader(),//做事的保证机制
															target.getClass().getInterfaces(),//要做的事物
    handler);//代理类的一个实例对象,用内部类创建实例对象new InvocationHandler(){invoke{target.invoke()}}
	
  interfaces.processBussiness();	//代理进行处理
	}
}


 class BussinessHandler implements InvocationHandler 
//代理类实现InvacationHandler,调用invoke方法
 {
	private Object target = null;
	public BussinessHandler(Object target)			
	{
		this.target = target;
	}
	public Object invoke(Object proxy, Method method, Object[] arrgs)   
			throws Throwable {
		System.out.println("you can do something here before process your bussiness:");
		Object result = method.invoke(target,arrgs);
		System.out.println("yon can do something here after process your bussiness");
		return result;
	}

}



class DoBussiness implements Bussinessy  //实现类
{
	public void processBussiness() {
		System.out.println("业务");
	}
}


interface Bussinessy		//业务接口,目标对象的方法
{
	public void processBussiness();
}

  

posted @ 2014-03-17 22:47  让痛苦变成美好的回忆  阅读(139)  评论(0编辑  收藏  举报