黑马程序员_代理

来源:互联网 发布:mac怎么显示隐藏的文件 编辑:程序博客网 时间:2024/05/18 20:08

---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IOS开发</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------
 

 

一、代理作用

        要为已存在的多个具有相同接口的目标类的各个方法增加一些系统功能,例如,异常处理、日志、计算方法的运行时间、事务管理、等等,在不对元程序进行修改的情况下,可以采用代理来完成。
        通过编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码。
       代理结构图
二、代理创建方式
        要为系统中的各种接口的类增加代理功能,那将需要太多的代理类,全部采用静态代理方式,将是一件非常麻烦的事情,因此实际开发过程中存在两种建立代理的方式
       1,JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。JVM生成的动态类必须实现一个或多个接口,所以,JVM生成的动态类只能用作具有相同接口的目标类的代理。
        此种创建代理的方式要求目标类要实现接口
        2,CGLIB库
        CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的类生成动态代理类,那么可以使用CGLIB库。
        这种方式可以对没有实现接口的目标类进行代理的创建
        3,代理类系统功能代码存放的位置
              3.1,在调用目标方法之前
              3.2,在调用目标方法之后
              3.3,在调用目标方法前后
              3.4,在处理目标方法异常的catch块中
三、创建动态代理类
       利用Proxy类的静态方法getProxyClass方法的到proxy类的class实例。
import java.lang.reflect.Proxy;import java.util.Collection;public class ProxyTest2 {/** * @param args */public static void main(String[] args) {Class clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);System.out.println(clazzProxy.getName());}}
       获取Proxy类的构造函数及参数
import java.lang.reflect.Constructor;import java.lang.reflect.Proxy;import java.util.Collection;public class ProxyTest2 {/** * @param args */public static void main(String[] args) {Class clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);System.out.println(clazzProxy.getName());//获取Proxy的构造函数Constructor[] constructors = clazzProxy.getConstructors();System.out.println(constructors.length);Constructor proxyConstructor = constructors[0];//获取构造函数的参数列表Class[] clazzParameterTypes = proxyConstructor.getParameterTypes();StringBuilder sb = new StringBuilder();sb.append(proxyConstructor.getName());for(Class clazzParameterType:clazzParameterTypes){sb.append("(");sb.append(clazzParameterType.getName());sb.append(")");}System.out.println(sb.toString());}}

四、创建动态代理类的对象

import java.lang.reflect.Constructor;import java.lang.reflect.InvocationHandler;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.util.ArrayList;import java.util.Collection;public class ProxyTest2 {/** * @param args * @throws Exception  * @throws   * @throws   * @throws   */public static void main(String[] args) throws Exception {Class clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);System.out.println(clazzProxy.getName());//获取Proxy的构造函数Constructor[] constructors = clazzProxy.getConstructors();System.out.println(constructors.length);Constructor proxyConstructor = constructors[0];//创建动态代理的对象Collection collection = (Collection)proxyConstructor.newInstance(new InvocationHandler() {ArrayList<String> al = new ArrayList<String>();Object retVal = null;@Override//复写invoke方法public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {retVal = method.invoke(al, args);return retVal;}});//调用代理类collection.add("1");collection.add("2");collection.add("3");System.out.println(collection.size());}}

五、动态生成的类的内部代码分析


       动态类在调用方法时将三要素作为参数传递给了InvocationHandler对象,InvocationHandler对象调用自己的invoke方法,并在内部调用目标类的方法,并且在内部还可以增加系统功能方法。

       动态代理的工作原理图

 

          在实际应用中将创建代理类封装成一个方法,并将系统的功能代码封装进对象,作为参数传递进去,通过调用这个对象的方法来完成系统的功能代码块。

 

 

 

---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IOS开发</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------详细请查看:<a href="http://edu.csdn.net" target="blank">http://edu.csdn.net</a>


 

 

 

 




 

 

0 0
原创粉丝点击