JAVA 动态代理原理和实现


在 Java 中动态代理和代理都很常见,几乎是所有主流框架都用到过的知识。在面试中也是经常被提到的话题,于是便总结了本文。

Java动态代理的基本原理为:被代理对象需要实现某个接口(这是前提),代理对象会拦截对被代理对象的方法调用,在其中可以全然抛弃被代理对象的方法实现而完成另外的功能,也可以在被代理对象方法调用的前后增加一些额外的功能。

动态代理可以为其他对象提供一个代理以控制对某个对象的访问。

代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。

JDK 动态代理

动态代理的核心其实就是代理对象的生成,即 Proxy.newProxyInstance(classLoader, proxyInterface, handler)。

让我们进入newProxyInstance方法观摩下,核心代码其实就三行。

这个方法需要三个参数:

  • ClassLoader,用于加载代理类的 Loader 类,通常这个 Loader 和被代理的类是同一个 Loader 类。
  • Interfaces,是要被代理的那些那些接口。
  • InvocationHandler,就是用于执行除了被代理接口中方法之外的用户自定义的操作,他也是用户需要代理的最终目的。用户调用目标方法都被代理到 InvocationHandler 类中定义的唯一方法 invoke 中。
1 2 3 4 5 6 //获取代理类   Class cl = getProxyClass(loader, interfaces);   //获取带有InvocationHandler参数的构造方法   Constructor cons = cl.getConstructor(constructorParams);   //把handler传入构造方法生成实例   return (Object) cons.newInstance(new Object[] { h });

一个典型的动态代理创建对象过程可分为以下四个步骤:

1、通过实现InvocationHandler接口创建调用处理器 

1 IvocationHandler handler = new InvocationHandlerImpl(...);

2、通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类

1 Class clazz = Proxy.getProxyClass(classLoader,new Class[]{...});

3、通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型

1 Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});

4、通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入

1 Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));

为了简化对象创建过程,Proxy类中的newProxyInstance方法封装了2~4,只需两步即可完成代理对象的创建。

1 2 Subject proxySubject = (Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(),         new Class[]{Subject.class}, new InvocationHandlerImpl (real));

生成的proxySubject继承Proxy类实现Subject接口。实现的Subject的方法实际是调用处理器的invoke方法,而invoke方法利用反射调用的是被代理对象的方法(Object result=method.invoke(proxied,args));
重点Proxy.newProxyInstance,源码分析,会在其他文档中单独总结记录。类Proxy的getProxyClass方法调用ProxyGenerator的 generateProxyClass方法产生ProxySubject.class的二进制数据。

创建代理对象时序图

创建代理对象时序图

获取代理类

getProxyClass(loader, interfaces)方法用于获取代理类,它主要做了三件事情:

在当前类加载器的缓存里搜索是否有代理类,没有则生成代理类并缓存在本地JVM里。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 // 缓存的key使用接口名称生成的List   Object key = Arrays.asList(interfaceNames);   synchronized (cache) {       do {   Object value = cache.get(key);            // 缓存里保存了代理类的引用   if (value instanceof Reference) {       proxyClass = (Class) ((Reference) value).get();   }   if (proxyClass != null) {   // 代理类已经存在则返回       return proxyClass;   else if (value == pendingGenerationMarker) {       // 如果代理类正在产生,则等待       try {   cache.wait();       catch (InterruptedException e) {       }       continue;   else {       //没有代理类,则标记代理准备生成       cache.put(key, pendingGenerationMarker);       break;   }       while (true);   }

生成并加载代理类

代理类的生成主要是以下这两行代码:

1 2 3 4 //生成代理类的字节码文件并保存到硬盘中(默认不保存到硬盘)    proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces);    //使用类加载器将字节码加载到内存中    proxyClass = defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);  

代理类的生成过程

ProxyGenerator.generateProxyClass()方法属于sun.misc包下,Oracle并没有提供源代码,但是我们可以使用
JD-GUI这样的反编译软件打开jre\lib\rt.jar来一探究竟,以下是其核心代码的分析。 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 //添加接口中定义的方法,此时方法体为空   for (int i = 0; i < this.interfaces.length; i++) {     localObject1 = this.interfaces[i].getMethods();     for (int k = 0; k < localObject1.length; k++) {        addProxyMethod(localObject1[k], this.interfaces[i]);     }   }   //添加一个带有InvocationHandler的构造方法   MethodInfo localMethodInfo = new MethodInfo("""(Ljava/lang/reflect/InvocationHandler;)V"1);   //循环生成方法体代码(省略)   //方法体里生成调用InvocationHandler的invoke方法代码。(此处有所省略)   this.cp.getInterfaceMethodRef("InvocationHandler""invoke""Object; Method; Object;")   //将生成的字节码,写入硬盘,前面有个if判断,默认情况下不保存到硬盘。   localFileOutputStream = new FileOutputStream(ProxyGenerator.access$000(this.val$name) + ".class");   localFileOutputStream.write(this.val$classFile);

生成的代理类源码

那么通过以上分析,我们可以推出动态代理为我们生成了一个这样的代理类。把方法doSomeThing的方法体修改为调用LogInvocationHandler的invoke方法。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class ProxyBusiness extends Proxy implements IBusiness, IBusiness2 {   private LogInvocationHandler h;   @Override   public void doSomeThing2() {       try {           Method m = (h.target).getClass().getMethod("doSomeThing2",null);           h.invoke(this, m, null);       catch (Throwable e) {           // 异常处理(略)       }   @Override   public boolean doSomeThing() {       try {          Method m = (h.target).getClass().getMethod("doSomeThing"null);          return (Boolean) h.invoke(this, m, null);       catch (Throwable e) {           // 异常处理(略)       }       return false;   }   public ProxyBusiness(LogInvocationHandler h) {       this.h = h;   }

测试代理的代码如下:

1 2 3 4 5 6 7 //测试 public static void main(String[] args) {       //构建AOP的Advice       LogInvocationHandler handler = new LogInvocationHandler(new Business());       new ProxyBusiness(handler).doSomeThing();       new ProxyBusiness(handler).doSomeThing2();   }

下面看一个自定义代理的实现。

被代理类接口

1 2 3 public interface Subject   {     public void doSomething();   }

被代理类

1 2 3 4 5 6 //目标对象 public class RealSubject implements Subject{   public void doSomething() {     System.out.println( "call doSomething()" );   } }

调用处理器(切面)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class ProxyHandler implements InvocationHandler   {     private Object proxied;     public ProxyHandler( Object proxied )   {       this.proxied = proxied;     }     public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable {   //在转调具体目标对象之前,可以执行一些功能处理 System.out.println( "doSomething before" );     //转调具体目标对象的方法     return method.invoke( proxied, args);  //在转调具体目标对象之后,可以执行一些功能处理 System.out.println( "doSomething after" );   } }

测试我们的代理实现

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class DynamicProxy   {     public static void main( String args[] )   {       RealSubject real = new RealSubject();       Subject proxySubject = (Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(),      new Class[]{Subject.class}, new ProxyHandler(real));     proxySubject.doSomething();     //write proxySubject class binary data to file       createProxyClassFile();     }     public static void createProxyClassFile()   {       String name = "ProxySubject";       byte[] data = ProxyGenerator.generateProxyClass( name, new Class[] { Subject.class } );       try{         FileOutputStream out = new FileOutputStream( name + ".class" );         out.write( data );         out.close();       }catch( Exception e ) {         e.printStackTrace();       }     }   }

运行结果:

1 2 3 doSomething before call doSomething() doSomething after

Proxy 接口

Proxy 的主要静态变量

1 2 3 4 5 6 7 8 9 10 11 12 13 // 映射表:用于维护类装载器对象到其对应的代理类缓存 private static Map loaderToCache = new WeakHashMap(); // 标记:用于标记一个动态代理类正在被创建中 private static Object pendingGenerationMarker = new Object(); // 同步表:记录已经被创建的动态代理类类型,主要被方法 isProxyClass 进行相关的判断 private static Map proxyClasses = Collections.synchronizedMap(new WeakHashMap()); // 关联的调用处理器引用 protected InvocationHandler h; Proxy的构造方法 // 由于 Proxy 内部从不直接调用构造函数,所以 private 类型意味着禁止任何调用 private Proxy() {} // 由于 Proxy 内部从不直接调用构造函数,所以 protected 意味着只有子类可以调用 protected Proxy(InvocationHandler h) {this.h = h;}

ProxySubject 源码

创建的代理类 ProxySubject.class

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 import java.lang.reflect.*;   public final class ProxySubject extends Proxy  implements Subject{       private static Method m1;       private static Method m0;       private static Method m3;       private static Method m2;       public ProxySubject(InvocationHandler invocationhandler){           super(invocationhandler);       }       public final boolean equals(Object obj){           try {               return ((Boolean)super.h.invoke(this, m1, new Object[] {                   obj               })).booleanValue();           }catch(Error _ex) {         }catch(Throwable throwable){               throw new UndeclaredThrowableException(throwable);           }       }       public final int hashCode()   {          try  {               return ((Integer)super.h.invoke(this, m0, null)).intValue();           }catch(Error _ex) {         }catch(Throwable throwable){               throw new UndeclaredThrowableException(throwable);           }       }       /*关键部分*/     public final void doSomething()  {           try {               // Proxy类中protected InvocationHandler h;关联的调用处理器引用             super.h.invoke(this, m3, null);               return;           }catch(Error _ex) {           }catch(Throwable throwable) {               throw new UndeclaredThrowableException(throwable);           }       }       public final String toString() {           try {               return (String)super.h.invoke(this, m2, null);           catch(Error _ex) {         catch(Throwable throwable){               throw new UndeclaredThrowableException(throwable);           }       }       static{           try {               m1 = Class.forName("java.lang.Object").getMethod("equals"new Class[] {                   Class.forName("java.lang.Object")               });               m0 = Class.forName("java.lang.Object").getMethod("hashCode"new Class[0]);               m3 = Class.forName("Subject").getMethod("doSomething"new Class[0]);               m2 = Class.forName("java.lang.Object").getMethod("toString"new Class[0]);           }catch(NoSuchMethodException nosuchmethodexception)   {               throw new NoSuchMethodError(nosuchmethodexception.getMessage());           }catch(ClassNotFoundException classnotfoundexception){               throw new NoClassDefFoundError(classnotfoundexception.getMessage());           }       }   }

CGLib 动态代理

动态字节码生成。使用动态字节码生成技术实现AOP原理是在运行期间目标字节码加载后,生成目标类的子类,将切面逻辑加入到子类中,所以使用Cglib实现AOP不需要基于接口。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public static void main(String[] args) {       byteCodeGe();   }   public static void byteCodeGe() {       //创建一个织入器       Enhancer enhancer = new Enhancer();       //设置父类       enhancer.setSuperclass(Business.class);       //设置需要织入的逻辑       enhancer.setCallback(new LogIntercept());       //使用织入器创建子类       IBusiness2 newBusiness = (IBusiness2) enhancer.create();       newBusiness.doSomeThing2();   }   /**   * 记录日志   */   public static class LogIntercept implements MethodInterceptor {       @Override       public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable {           //执行原有逻辑,注意这里是invokeSuper           Object rev = proxy.invokeSuper(target, args);           //执行织入的日志           if (method.getName().equals("doSomeThing2")) {               System.out.println("记录日志");           }           return rev;       }   }

转自:https://www.xttblog.com/?p=2732