java使用反射生成JDK动态代理

一、基本简介 在java的java.lang.reflect包下提供了一个Proxy类和InvocationHandler接口,通过使用这个类和接口可以生成JDK动态代理类或动态代理对象。

Proxy类提供了两个方法:

  1. static Class< ? > getProxyClass( ClassLoader loader,Class< ? > … interfaces) : 创建一个动态代理类所对应的Class对象,该代理类将实现interfaces所指定的多个接口。 第一个参数指定生成动态代理类的类加载器。
  2. static Object newProxyInstance( ClassLoader loader,Class< ? >[] interfaces,InvocationHandler h): 直接创建一个动态代理对象,该代理对象的实现类实现了Interfaces指定的系列接口,执行代理对象的每个方法都会被替换成InvocationHandler对象的invoke方法。

实际上,即使采用第一种方法生成动态代理类之后,如果程序需要通过该代理类来创建代理对象,还是需要传入一个InvocationHandler实例。

代码示例:

try {
      //创建一个InvocationHandler对象
      InvocationHandler invocationHandler = new MyInvocationHandler();
      //使用Proxy生成一个动态代理类proxyClass
      Class proxyClass= Proxy.getProxyClass(Foo.class.getClassLoader(),Foo.class);
      //获取一个proxyClass类带InvocationHandler参数的构造器
      Constructor constructor = proxyClass.getConstructor(InvocationHandler.class);
      //调用constructor的newInstance方法生成动态代理实例
      Foo foo = (Foo) constructor.newInstance(invocationHandler);
    } catch (Exception e) {
      e.printStackTrace();
    }

以上的代码可以简化为下面的代码

InvocationHandler invocationHandler = new MyInvocationHandler();
    Foo foo= (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class[]{Foo.class},invocationHandler);

二、实践操作

public interface Person {
          
   
  void sleep();
}

public class Man implements Person {
          
   
  @Override public void sleep() {
    System.out.println("开始睡觉了");
  }
}

public class LogUtil {
          
   
  public void filter1(){
    System.out.println("在代理对象的方法执行之前,进行拦截做点什么");
  }
  public void filter2(){
    System.out.println("在代理对象的方法执行之后,进行拦截做点什么");
  }
}

生成代理对象

public class MyProxyFactory {
  public static  Object getProxy(Object target){
    MyInvocationHandler handler = new MyInvocationHandler();
    handler.setTarget(target);
    return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),handler);
  }
}
public class MyInvocationHandler implements InvocationHandler {
          
   
  //需要被代理的对象
  private Object target;
  public void setTarget(Object target){
    this.target=target;
  }
  //1.proxy代表动态代理的对象
  //2.method代表正在执行的方法
  //3.args代表调用目标方法时传入的实参
  @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    LogUtil log = new LogUtil();
    log.filter1();
    //通过反射执行动态代理对象的所有方法
    Object obj=method.invoke(target,args);
    log.filter2();
    return obj;
  }
}
public static void main(String[] args){
    Person target = new Man();
    Person man= (Person) MyProxyFactory.getProxy(target);
    man.sleep();
  }

运行结果:

三、总结 一般普通编程无需用到动态代理,但在编写框架或底层代码时,它的作用就非常大了。还有就是使用动态代理可以非常灵活的实现解耦。

参考《疯狂java讲义》

经验分享 程序员 微信小程序 职场和发展