深入剖析JDK动态代理实现原理

一.前言

动态代理是目前使用的比较广泛技术,大家都比较熟悉的框架比如Spring中的AOP特性就用到了动态代理

二、动态代理使用示例

比如说有一个业务需要我们在添加或者删除用户的时候,将信息添加到日志当中,但是把日志的代码插入原有的业务代码中是很不雅观的,为了不破坏原有的实现类,这时候我们就可以用到动态代理。

接口类

public interface UserService {
	public void add();
	public void delete(int id);
} 

实现类

public class UserServiceImpl implements UserService{
	@Override
	public void add() {
		System.out.println("add");
	}
	@Override
	public void delete(int id) {
		System.out.println("delete:"+id);
	}
}
使用JDK的动态代理首先要实现InvocationHandler接口
package com.zhu.proxy.jdk;

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

public class MyInvocationHandler implements InvocationHandler{
    //用户服务实现类的实例
    private Object target;
    public MyInvocationHandler(Object target){
        this.target=target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // TODO Auto-generated method stub
        String name=method.getName();
        if("add".equals(name)){
            System.out.println("用户添加");
        }else if("delete".equals(name)){
            System.out.println("用户删除");
        }
        //真正执行业务的地方
        Object result=method.invoke(target, args);
        return result;
    }

}
main

System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); 这句设置系统属性,使得JVM产生的代理类都可以保存在文件中 路径为:com/sun/proxy,需要手动的在项目的根目录创建路径,如图深入剖析JDK动态代理实现原理_第1张图片

注意生成的为代理类的class文件,此时还需要使用反编译工具(百度一下反编译工具即可下载)将其转换为大家都能看懂的java文件

package com.zhu.proxy.jdk;

import java.lang.reflect.Proxy;

public class TestProxy {
	public static void main(String[] args) {
		//设置系统属性,使得JVM产生的代理类都可以保存在文件中 路径为:com/sun/proxy
		System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
		UserServiceImpl userService=new UserServiceImpl();
		MyInvocationHandler h=new MyInvocationHandler(userService);
		//proxy为生成的代理类对象
		UserService proxy=(UserService)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),userService.getClass().getInterfaces(),h);
		proxy.add();
		proxy.delete(1);
	}
}
运行结果
深入剖析JDK动态代理实现原理_第2张图片
反编译后的代理类代码:

package com.sun.proxy;

import com.zhu.proxy.jdk.UserService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0
  extends Proxy
  implements UserService
{
  private static Method m1;
  private static Method m3;
  private static Method m4;
  private static Method m0;
  private static Method m2;
  
  public $Proxy0(InvocationHandler paramInvocationHandler)
    throws 
  {
    super(paramInvocationHandler);
  }
  
  public final boolean equals(Object paramObject)
    throws 
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final void add()
    throws 
  {
    try
    {
      this.h.invoke(this, m3, null);
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final void delete(int paramInt)
    throws 
  {
    try
    {
      this.h.invoke(this, m4, new Object[] { Integer.valueOf(paramInt) });
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final int hashCode()
    throws 
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final String toString()
    throws 
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("com.zhu.proxy.jdk.UserService").getMethod("add", new Class[0]);
      m4 = Class.forName("com.zhu.proxy.jdk.UserService").getMethod("delete", new Class[] { Integer.TYPE });
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}
可以看到代理类中,我们需要被代理的方法add(),和delete()的实现中都是直接调用InvovationHandler中的invoke方法

三、实现原理

代理类的生成是由该行代码实现(为了方便理解以下源码为简化后的伪代码,只保留了最重要的部分

Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),userService.getClass().getInterfaces(),h);

public static Object newProxyInstance(ClassLoader loader,
                                          Class[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
       
        final Class[] intfs = interfaces.clone();
        // 获取代理类的Class对象
        Class cl = getProxyClass0(loader, intfs);
   //根据参数获取构造函数
    final Constructor cons = cl.getConstructor(constructorParams);
       //生成代理类的实例
        return newInstance(cons, ih);
      
    }
 private static Object newInstance(Constructor cons, InvocationHandler h) {
            return cons.newInstance(new Object[] {h} );
    }
 newInstance方法很简单,就是通过反射来实例化对象

在接着看getProxyClass0方法

  private static Class getProxyClass0(ClassLoader loader,
                                           Class... interfaces) {

        return proxyClassCache.get(loader, interfaces);
    }
首先会在缓存中查到是否该类加载器已经加载过该代理类,如果找到则直接返回,否则使用 ProxyClassFactory来生成代理类
 public Class apply(ClassLoader loader, Class[] interfaces) {
            long num = nextUniqueNumber.getAndIncrement();
//拼接代理类名
  String proxyName = proxyPkg + proxyClassNamePrefix + num;
           //生成字节码
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces);
             // 通过类加载器生成代理类的Class对象
                return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
    
    }
到这里相信大家对JDK动态代理的使用和原理也有了一定的了解。

你可能感兴趣的:(Java,动态代理)