欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java 动态代理

程序员文章站 2022-06-09 21:39:45
...

动态代理是一种运行期动态生成字节码的手段,除此之外生成字节码的手段还有诸如JSP编译器,编译时植入的AOP框架等,这里不做过多的赘述。相信即使是没有使用过动态代理,那么也应该用过Spring来做过Bean的管理,如果Bean是面向接口编程,那么Spring内部都是通过动态代理来实现对Bean的增强。动态代理中所谓的“动态”,是相对于使用Java代码实际编写了代理类的“静态”代理而言,它的优势不在于省去了编写静态类的那点代码,而是实现了在原始类与接口还未知的时候,就确定了代理类的代理行为。

上文红色字段便是动态代理区别于静态代理的精髓所在,若想对动态代理有深入的理解,先对静态代理有一个深刻的认识绝对是最优解。下面来看一个静态代理的例子。

public class StaticProxyTest {
    public static void main(String[] args) {
        Hello origin = new IHello();
        StaticProxy proxy = new StaticProxy(origin);
        proxy.sayHello();
    }
    //接口
    static interface Hello {
        public void sayHello();
    }
    //被代理类
    static class IHello implements Hello {
        @Override
        public void sayHello() {
            System.out.println("I'm Chinese.");
        }
    }
    //静态代理类
    static class StaticProxy implements Hello {
        //接收一个被代理对象
        private Hello origin;

        public StaticProxy(Hello origin) {
            this.origin = origin;
        }
        //代理行为
        @Override
        public void sayHello() {
            System.out.println("Hello world.");
            origin.sayHello();
        }
    }


}

静态代理的核心用一句话概括:编写一个代理类,实现与被代理类相同的接口,注入一个被代理对象,在方法重写中实现代理行为

动态代理的核心依旧是接口、被代理对象、代理行为,只不过用到了其他的手段来实现,过程更加抽象,不关注实际的接口,被代理类,只关注代理行为。从而导致一种代理行为可以作用于千万种被代理类。动态代理需要用到java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler。下面来看一个动态代理的例子。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class DynamicProxyTest {
  public static void main(String[] args) {
    //代理对象
    Object proxy = new DynamicProxy().bind(new IHello());
    ((Hello)proxy).sayHello();
  }
  //接口
  static interface Hello {
    void sayHello();
  }
  //被代理类
  static class IHello implements Hello {

    @Override
    public void sayHello() {
      System.out.println("I'm Chinese.");
    }
  }

  //InvocationHandler
  static class DynamicProxy implements InvocationHandler {
    //被代理对象
    private Object origin;

    //生成代理对象
    public Object bind(Object origin) {
      this.origin = origin;
      return Proxy.newProxyInstance(
        //被代理对象的ClassLoader
        origin.getClass().getClassLoader(),
        //被代理对象所实现的接口
        origin.getClass().getInterfaces(),
        //handler
        this);
    }

    //代理行为
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      System.out.println("Hello world.");
      //通过反射执行被代理对象的原方法
      return method.invoke(origin, args);
    }
  }

}

如果被代理类实现了多个接口,那么动态代理便对所有方法实现了相同的代理行为。