zoukankan      html  css  js  c++  java
  • 动态代理

    一、什么是动态代理

    代理很容易理解,就很生活中很容易接触的代理商,动态代理的关键在于动态,也就是说这个代理商是动态创建出来的 ,是一个产品已经上线销售了,突然呢又想添加一个新的代理商,就动态的生成一个呗,,而且不会有影响其他代理商。

    二、动态代理机制中的重要的接口和类

    一个类:java.lang.reflect.Proxy:
    java.lang.reflect.Proxy:这是 Java 动态代理机制的主类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。
    // 方法 1: 该方法用于获取指定代理对象所关联的调用处理器
    static InvocationHandler getInvocationHandler(Object proxy)
    // 方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象
    static Class getProxyClass(ClassLoader loader, Class[] interfaces)
    // 方法 3:该方法用于判断指定类对象是否是一个动态代理类
    static boolean isProxyClass(Class cl)
    // 方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
    static Object newProxyInstance(ClassLoader loader, Class[] interfaces,
        InvocationHandler h)
    其中在动态代理中用于动态生成代理商的方法就是方法4:
    static Object newProxyInstance(ClassLoader loader, Class[] interfaces,InvocationHandler h)
    参数列表:   
    loader:      一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
    interfaces:  一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了 
    h:          一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
     
    一个接口:java.lang.reflect.InvocationHandler
    java.lang.reflect.InvocationHandler:这是调用处理器接口,它自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。
    InvocationHandler 的核心方法
    Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    
    proxy:  指代我们所代理的那个真实对象
    method:  指代的是我们所要调用真实对象的某个方法的Method对象
    args:  指代的是调用真实对象某个方法时接受的参数
    三、实现一个动态代理
    刚才看了一些动态代理的概念,可能只是知道是动态生成代理商,并不知道如何实现,也不知道那一个类,一个接口是如何用,现在先举个例子来实现一下动态代理来感受一下
    场景假设:就是一个手机厂商,生产出新手机了正在热卖,需要找代理商进行销售的扩展;
    (1)创建手机接口
     package com.neuedu.java.phoneProxy;
    /* 
    * 项目名称:Java-Proxy 
    * @author:wzc
    * @date 创建时间:2017年8月30日 下午9:00:49
    * @Description:一个手机接口
    * @parameter 
    * */
    public interface Phone {
     public void sellPhone();
    }
    

    (2)一款具体的手机类-----手机一代
    package com.neuedu.java.phoneProxy;
    /* 
    * 项目名称:Java-Proxy 
    * @author:wzc
    * @date 创建时间:2017年8月30日 下午9:02:26
    * @Description:第一代手机,实现手机接口
    * @parameter 
    * */
    public class phoneOne implements Phone{
     
     @Override
     public void sellPhone() {
     System.out.println("我是第一代手机,现在正在热销中");
     }
    }
    

    (3)处理代理商的中介类--------作为调用处理器”拦截“对代理类方法的调用
    中介类持有一个委托类对象引用,在invoke方法中调用了委托类对象的相应方法
    package com.neuedu.java.phoneProxy;
     
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
     
    /*
    * 项目名称:Java-Proxy
    * @author:wzc
    * @date 创建时间:2017年8月30日 下午9:03:49
    * @Description:中介类,中介类持有一个委托类对象引用,在invoke方法中调用了委托类对象的相应方法
    * @parameter
    * */
    public class phoneProxy implements InvocationHandler{
    private Object obj;
     
     public phoneProxy(Object obj) {
         this.obj=obj;
      }
     
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object result = method.invoke(obj, args);
                return result;
      }
     
    }
    

    (4)测试------动态生成代理商
    package com.neuedu.java.junit;
     
    import static org.junit.Assert.*;
     
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
     
    import org.junit.Test;
     
    import com.neuedu.java.phoneProxy.Phone;
    import com.neuedu.java.phoneProxy.phoneOne;
    import com.neuedu.java.phoneProxy.phoneProxy;
     
    /*
    * 项目名称:Java-Proxy
    * @author:wzc
    * @date 创建时间:2017年8月30日 下午9:05:45
    * @Description:测试动态代理
    * @parameter
    * */
    public class testPhoneProxy {
     
    @Test
    public void test() {
        //创建 一个被代理的对象
        Phone phone_one=new phoneOne();
        //将被代理的对象加入中介类
        InvocationHandler handler=new phoneProxy(phone_one);
        //动态的生成代理类,和被代理的对象类类型相同
        Phone phoneProxy_one = (Phone)    
    Proxy.newProxyInstance(handler.getClass().getClassLoader(), phone_one.getClass().getInterfaces(), handler); //代理商销售手机 phoneProxy_one.sellPhone(); } }

    看到这应该对动态代理有了那么一丝丝感觉了,因为动态代理就这么四步就实现了不是吗?
    现在让我们看看动态代理的原理吧:
    四、动态代理机制
    具体有如下四步骤:
    1. 通过实现 InvocationHandler 接口创建自己的调用处理器;
    2. 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
    3. 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
    4. 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
    其实动态代理就是一类一接口实现的,只要弄懂InvocationHandler 接口,和 Proxy 类,动态代理的原则也就懂了。
     
     
    (2)Proxy类是通过newProxyInstance()方法生成代理类的,那我们就来看看他是怎么生成的
     
    tatic Object newProxyInstance(ClassLoader loader, Class[] interfaces,
        InvocationHandler h)
    第一个参数:java.lang.ClassLoader:这是类装载器类,负责将类的字节码装载到 Java 虚拟机(JVM)中并为其定义类对象,然后该类才能被使用。Proxy 静态方法生成动态代理类同样需要通过类装载器来进行装载才能使用,它与普通类的唯一区别就是其字节码是由 JVM 在运行时动态生成的而非预存在于任何一个 .class 文件中。
     
    public static Object newProxyInstance(ClassLoader loader,
                Class<?>[] interfaces,
                InvocationHandler h)
                throws IllegalArgumentException {
         
        // 检查 h 不为空,否则抛异常
        if (h == null) {
            throw new NullPointerException();
        }
     
        // 获得与制定类装载器和一组接口相关的代理类类型对象
        Class cl = getProxyClass(loader, interfaces);
     
        // 通过反射获取构造函数对象并生成代理类实例
        try {
            Constructor cons = cl.getConstructor(constructorParams);
            return (Object) cons.newInstance(new Object[] { h });
        } catch (NoSuchMethodException e) { throw new InternalError(e.toString());
        } catch (IllegalAccessException e) { throw new InternalError(e.toString());
        } catch (InstantiationException e) { throw new InternalError(e.toString());
        } catch (InvocationTargetException e) { throw new InternalError(e.toString());
        }
    }
    

     

     
     

     
    可以看出来Proxy类就是通过反射的思想来生成动态代理对象的,唯一关键是在 getProxyClass 方法,该方法负责为一组接口动态地生成代理类类型对象。
  • 相关阅读:
    request.getParameter() 和request.getAttribute() 区别
    Java中this和super的用法总结
    jQuery实现列表框双向选择操作
    Eclipse中.setting目录下文件介绍
    通过Ajax方式上传文件,使用FormData进行Ajax请求
    ASP.NET程序中常用的三十三种代码
    计算地球上两个坐标点(经度,纬度)之间距离sql函数
    动态调用WebService(C#) (非常实用)
    带SoapHeader验证的WebServices
    GridView内容详解(转载)
  • 原文地址:https://www.cnblogs.com/Actexpler-S/p/7455649.html
Copyright © 2011-2022 走看看