首页 > 代码库 > 反射机制-动态代理

反射机制-动态代理

目标:

掌握代理机制的作用

掌握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) ;    // 调用方法            

 

 

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

反射机制-动态代理