zoukankan      html  css  js  c++  java
  • 反射机制-动态代理

    目标:

    掌握代理机制的作用

    掌握InvocationHandler接口,和Proxy类的作用。

    具体内容

    代理设计,一个操作的接口有两个子类,其中一个是真实主题的实现类。另一个是代理实现类。

    可以复习之前的代理设计模式:

    接口与抽象类的应用(包括各自设计模式)

    代理实现类需要完成比真实主题实现类更多的内容,而且本身还需要处理一些与具体业务有关的程序代码。

    普通代理实例:

    package 类集;
    interface Subject{
        public String say(String name,int age) ;    // 定义抽象方法say
    }
    class RealSubject implements Subject{    // 实现接口
        public String say(String name,int age){
            return "姓名:" + name + ",年龄:" + age ;
        }
    };
    class ProxySubject implements Subject{
        Subject b=null;
        public ProxySubject(Subject b)
        {
            this.b=b;
        }
        public String say(String name,int age)
        {
             return this.b.say(name, age);
        }
    }
    public class GetInterfaceDemo {
        public static void main(String[] args) throws Exception {
            Subject b1=new ProxySubject(new RealSubject());
            System.out.print(b1.say("小红", 23));
        }
    
    }

    以上代理操作实际被称为静态代理,因为一个代理类,只能为一个接口服务,那么如果有很多接口,则代理类很多。

    而且,所有代理操作除了调用的方法不一样,其他操作都一样,则此时肯定重复代码了

    InvocationHandler接口

    接口:

    public interface InvocationHandler

    接口中方法:

     Object invoke(Object proxy, Method method, Object[] args) 
              在代理实例上处理方法调用并返回结果。 

    proxy - 被代理的对象

    method - 要调用的方法。

    args - 方法调用时所需参数

    可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject。如下:

    class MyInvocationHandler implements InvocationHandler{
        
        public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
        }
    };

    Proxy类

    Proxy类是专门的完成代理的操作类,可以通过此类为一个或多个接口动态的实现类,此类提供以下操作方法。

    static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 
              返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。 

    参数说明:

    ClassLoader loader:类加载器

    interfaces:得到全部的接口

    h:得到InvocationHandler接口的子类实例。

    ClassLoader表示类的加载器,对于java类来说,类加载器主要有三种。

    1)Bootstrap ClassLoader2)Extention ClassLoader3)AppClassLoader:加载classpath指定的类,是最常用的加载器。

    如果要得到一个加载器对象,肯定使用Class类完成

    取得类加载器实例:

    package 类集;
    class Person{};
    public class GetInterfaceDemo {
        public static void main(String[] args) throws Exception {
            Person stu = new Person() ;
    //相当于通过一个Class类对象获取类加载器,然后对这个类加载器,获取它的Class类对象,再获取这个类对象名称 System.out.println(
    "类加载器:" + stu.getClass().getClassLoader().getClass().getName()) ; } }

    输出结果:

    类加载器:sun.misc.Launcher$AppClassLoader

    动态代理实例:

    package 类集;
    
    import java.lang.reflect.Array;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    interface Subject{            //定义一个接口
        public String say(String name,int age) ;    // 定义抽象方法say
    }
    class RealSubject implements Subject{    // 实现接口
        public String say(String name,int age){
            return "姓名:" + name + ",年龄:" + age ;
        }
    };
    class MyInvocationHandler implements InvocationHandler{
        private Object obj ; //真实主题
        public Object bind(Object obj){    //绑定真实操作主题
            this.obj = obj ;   
            return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this) ;//取得代理对象
        }
        public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{  //动态调用方法
            this.before();
         Object temp
    = method.invoke(this.obj,args) ; // 调用方法,传人真实主题和参数 return temp ;      //返回方法的返回信息 }
       public void before()
      {
        System.out.Println("代理之前");
      }
    };
    public class GetInterfaceDemo { public static void main(String[] args) throws Exception { Subject sub = (Subject)new MyInvocationHandler().bind(new RealSubject()) ;//通过bind()方法返回一个Proxy对象给sub,并且需要转换类型。 String info = sub.say("小华",30) ; System.out.println(info) ; } }

    输出结果:

    代理之前
    姓名:小华,年龄:30

     代码讲解:

     public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{  //动态调用方法
         Object temp = method.invoke(this.obj,args) ;    // 调用方法,传人真实主题和参数
            return temp ;      //返回方法的返回信息
        }

    这个方法是在真实主题对象调用方法的时候自动调用

    至于method.invoke(),复习前面知识。

    执行调用的方法:Method类中的invoke()

     Object invoke(Object obj, Object... args) 
              对带有指定参数的指定对象调用由此 Method 对象表示的底层方法

    里面的this.obj就是RealSubject的实例对象,args就是调用say()方法时候传人的参数:小华,30。

    里面的method,调用哪个方法,这个method就表示哪个方法,因此他invoke里面的参数就带什么。

    比如这里调用了say(String name,int age),相当于做了以下操作:

     Method  met = obj.getClass().getMethod("sayHello",String.class,int.class) ;  
                 met.invoke(c1.newInstance(),"小华",30) ;    // 调用方法            

    发现,使用动态代理,就可以完成代理功能,而且可以代理全部接口。

  • 相关阅读:
    索引查找Java实现
    经典算法之折半查找
    进制转换问题
    排序算法总结之希尔排序
    自己写的栈
    排序问题Java
    画柱状图Java
    一些值得看的性能优化的文章
    理解 BFC
    canvas
  • 原文地址:https://www.cnblogs.com/alsf/p/6597387.html
Copyright © 2011-2022 走看看