详解java设计模式(五)之代理模式下篇(结构型)

    xiaoxiao2021-03-25  75

    引言:

    一般来说,对代理模式而言,一个主题类与一个代理类一一对应,这也是静态代理模式的特点。但是,也存在这样的情况,有n各主题类,但是代理类中的“前处理、后处理”都是一样的,仅调用主题不同。也就是说,多个主题类对应一个代理类,共享“前处理,后处理”功能,动态调用所需主题,大大减小了程序规模,这就是动态代理模式的特点。

    一.jdk下的动态代理基础知识

    1,Java.lang.reflect.Proxy:

    动态代理机制的主类,提供一组静态方法为一组接口动态的生成对象和代理类。(需要一定的反射基础)

    // method1: 该方法用于获取指定代理对象所关联的调用处理器 public static InvocationHandler getInvocationHandler(Object proxy) // method 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象 public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) // method 3:该方法用于判断指定类对象是否是一个动态代理类 public static boolean isProxyClass(Class<?> cl) //methods 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例 public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)2,java.lang.reflect.InvocationHandler:

    调用处理器接口,自定义invokle方法,用于实现对于真正委托类的代理访问。

    /** 该方法负责集中处理动态代理类上的所有方法调用。 第一个参数是代理类实例, 第二个参数是被调用的方法对象 第三个方法是调用参数。 调用处理器根据这三个参数进行预处理或分派到委托类实例上发射执行 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;3,java.lang.ClassLoader:

    类装载器类,将类的字节码装载到 Java 虚拟机(JVM)中并为其定义类对象,然后该类才能被使用。Proxy类与普通类的唯一区别就是其字节码是由 JVM 在运行时动态生成的而非预存在于任何一个 .class 文件中。 每次生成动态代理类对象时都需要指定一个类装载器对象:newProxyInstance()方法第一个参数

    二.动态代理实现

    1.动态代理实现步骤

    1) 创建被代理的类及接口

    2) 创建一个实现InvocationHandler接口的类,它必须实现invoke()方法(对被代理类进行代理的实现类)

    3.) 调用Proxy的静态方法,创建一个代理类

    4.) 通过代理调用方法

    2.编程实现demo

     1)创建被代理的类及接口

    public interface Login { //验证用户名 public void validate(String username); //打印日志 public void printLog(); } //被代理类 public class MyLogin implements Login { @Override public void validate(String username) { System.out.println("查询数据库,核对用户"); } @Override public void printLog() { System.out.println("print log"); } }2)创建一个实现InvocationHandler接口的类,它必须实现invoke()方法

    import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class myHandler implements InvocationHandler { public Object target; public myHandler(Object target){ this.target=target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("进入method"+method.getName()); //如果为validate方法则判断地一个参数是否为admin if("valiate".equals(method.getName())){ if("admin".equals(args[0])) System.out.println("记录系统用户"); } Object c=method.invoke(target,args); return c; } }

    3) 调用代理类实现

    import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class ProxyTest { public static void main(String[] args){ //通过实现 InvocationHandler 接口创建自己的调用处理器; //通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类; //通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型 //通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入 Login mylogin=new MyLogin(); InvocationHandler h=new myHandler(mylogin); Class<?> cls = mylogin.getClass(); /** *loader 类加载器 *interfaces 实现接口 *h InvocationHandler */ Login m = (Login) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(), h); m.validate("admin"); m.printLog(); } }从这里可以知道动态代理实现了较大程度上的灵活性,但一般动态代理的执行效率不是很高。

    三.jdk动态代理proxy原理及参考资料

    想要深入理解动态代理模式的可以看这篇文章 代理模式深入分析

    看完上面这篇文章后,最大的收获应该是对动态代理有了深入的了解,特别是最后一个模拟动态代理的实例,使得对我们动态代理认识更深,

    本质上仍是有关反射,类装载的那些知识。

    下面我们将动态代理实现类可能实现方式贴在下方,便于理解。

    package mydp; import java.lang.reflect.*; // 假设代理类为 ProxyLogin, 其类声明将如下 public class ProxyLogin implements Login { // 调用处理器对象的引用 protected InvocationHandler handler; // 以调用处理器为参数的构造函数 public ProxyLogin(InvocationHandler handler){ this.handler = handler; } @Override public void validate(String username) { Method method=null; Object r=null; try { method = Login.class.getMethod( "validate", new Class[] {String.class} ); } catch (Exception e) { } try { r = handler.invoke(this,method,// 对于原始类型参数需要进行装箱操作 new Object[] {username}); } catch (Throwable e) { } } @Override public void printLog() { //参考validate实现 } }上面代码虽然不一定是jdk中的实现方法,但是对于我们理解动态代理模式却是非常重要的。其中反射是实现动态代理最重要的基础

    转载请注明原文地址: https://ju.6miu.com/read-32282.html

    最新回复(0)