黑马程序员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(); }