JDK 动态代理 原理分析

代理是一种常用的设计模式,所谓代理模式是指客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象。

代理模式可以有两种实现的方式,一种是静态代理类,另一种是各大框架都喜欢的动态代理。

静态代理模式相对简单,类图如下

代理类接受一个Subject接口的对象,任何实现该接口的对象,都可以通过代理类进行代理,增加了通用性。但是也有缺点,每一个代理类都必须实现一遍委托类(也就是realsubject)的接口,如果接口增加方法,则代理类也必须跟着修改。其次,代理类每一个接口对象对应一个委托对象,如果委托对象非常多,则静态代理类就非常臃肿,难以胜任。


动态代理有别于静态代理,是根据代理的对象,动态创建代理类。这样,就可以避免静态代理中代理类接口过多的问题。动态代理是实现方式,是通过反射来实现的。Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类

(1)Interface InvocationHandler:该接口中仅定义了一个方法

public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;


在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。这个抽象方法在代理类中动态实现。

(2)Proxy:该类即为动态代理类,其中主要包含以下内容:

protected Proxy(InvocationHandler h)


构造函数,用于给内部的h赋值。

public static Class<?> getProxyClass(ClassLoader loader,
                                         Class<?>... interfaces)


获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在接口中声明过的方法)


所谓DynamicProxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些 interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然,这个DynamicProxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。


在使用动态代理类时,我们必须实现InvocationHandler接口


通过这种方式,被代理的对象可以在运行时动态改变,需要控制的接口(Subject接口)可以在运行时改变,控制的方式也可以动态改变,从而实现了非常灵活的动态代理关系。

动态代理步骤
1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法
2.创建被代理的类以及接口
3.通过Proxy的静态方法
newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理
4.通过代理调用方法


jdk动态代理的使用

1、需要动态代理的接口:

package proxy;

public interface UserInterface {
    public void methodPublic1();
    public void methodPublic2(String a);
    void defaultMethod1(int b);
    void defaultMethod2();
}

这里声明了4个方法


2、需要代理的实际对象

package proxy;

public class UserReal implements UserInterface {

	@Override
	public void methodPublic1() {
		System.out.println("methodPublic1");
	}

	@Override
	public void methodPublic2(String a) {
		System.out.println(a+"========methodPublic2");
	}

	@Override
	public void defaultMethod1(int b) {
		System.out.println(b+"========defaultMethod1");
	}

	@Override
	public void defaultMethod2() {
		System.out.println("defaultMethod2");
	}

}


3、调用处理器实现类

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

public class TestInvocationHandler implements InvocationHandler {

	//要代理的真实对象
	private Object target;

	//构造方法,给我们要代理的真实对象赋初值
	public TestInvocationHandler(Object target) {

		super();
		this.target = target;

	}

	/** 
     * 该方法负责集中处理动态代理类上的所有方法调用。 
     * 调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行 
     * 
     * @param proxy  代理类实例 
     * @param method 被调用的方法对象 
     * @param args   调用参数 
     * @return 
     * @throws Throwable 
     */ 
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		System.out.println("调用方法     "+method);
		System.out.println("-----------------调用方法前 -----------------");
		//当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用  
        Object result = method.invoke(target, args);
        System.out.println("-----------------调用方法后-----------------");
        return result;
	}

}


4、测试

public class Test {

	public static void main(String[] args) throws Exception{
		/* 设置此系统属性,让JVM生成的Proxy类写入文件.保存路径为:com/sun/proxy(如果不存在请手工创建) */  
          System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");  
          System.out.println(Proxy.getProxyClass(UserInterface.class.getClassLoader(), UserInterface.class));  
		  UserInterface user = new UserReal();
		  TestInvocationHandler handler = new TestInvocationHandler(user);

		  ClassLoader loader = user.getClass().getClassLoader();  
	      Class[] interfaces = user.getClass().getInterfaces();
	      
		  UserInterface proxy =(UserInterface)Proxy.newProxyInstance(loader, interfaces,
					handler);
		  proxy.methodPublic1();
		  proxy.methodPublic2("公共2");
		  proxy.defaultMethod1(10000);
		  proxy.defaultMethod2(); 
	}

}


5、输出结果如下


动态代理是如何实现的

关键代码如下

UserInterface proxy =(UserInterface)Proxy.newProxyInstance(loader, interfaces,
					handler);

通过跟踪提示代码可以看出:当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用。

也就是说,当代码执行到:

proxy.methodPublic1()这句话时,会自动调用InvocationHandlerImpl的invoke方法。这是为啥呢?

我们看看Proxy类的静态方法newProxyInstance的源码

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        if (h == null) {
            throw new NullPointerException();
        }

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * 获得与指定类装载器和一组接口相关的代理类类型对象
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            //获取代理对象的构造方法(也就是$Proxy0(InvocationHandler h))  
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
                // create proxy instance with doPrivilege as the proxy class may
                // implement non-public interfaces that requires a special permission
                return AccessController.doPrivileged(new PrivilegedAction<Object>() {
                    public Object run() {
                        return newInstance(cons, ih);
                    }
                });
            } else {
             //生成代理类的实例并把InvocationHandlerImpl的实例传给它的构造方法
                return newInstance(cons, ih);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString());
        }
    }

进入getProxyClass0(loader, intfs),我们可以看到最关键的代码是

byte[] proxyClassFile = ProxyGenerator.generateProxyClass(  
               proxyName, interfaces, accessFlags);  

那么接下来我们也使用测试一下,使用这个方法生成的字节码是个什么样子

public class Test {

	public static void main(String[] args) throws Exception{

		  UserInterface user = new UserReal();
	          Class[] interfaces = user.getClass().getInterfaces()
		  
		  String name = "ProxyUser";
		  byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                 name , interfaces);
		  FileOutputStream out =null;  
	        try {  
	            out = new FileOutputStream("d:/"+name+".class");  
	            out.write(proxyClassFile);  
	        } catch (FileNotFoundException e) {  
	            e.printStackTrace();  
	        } catch (IOException e) {  
	            e.printStackTrace();  
	        }finally {  
	            if(null!=out) try {  
	                out.close();  
	            } catch (IOException e) {  
	                e.printStackTrace();  
	            }  
	        }   
	}

}

我们在d盘可以找到ProxyUser.class,用反编译工具打开可以看到

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import proxy.UserInterface;

public final class ProxyUser extends Proxy
  implements UserInterface
{
  private static Method m1;
  private static Method m5;
  private static Method m6;
  private static Method m0;
  private static Method m4;
  private static Method m3;
  private static Method m2;

  public ProxyUser(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 (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

  public final void defaultMethod1(int paramInt)
    throws 
  {
    try
    {
      this.h.invoke(this, m5, new Object[] { Integer.valueOf(paramInt) });
      return;
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

  public final void defaultMethod2()
    throws 
  {
    try
    {
      this.h.invoke(this, m6, null);
      return;
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

  public final int hashCode()
    throws 
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

  public final void methodPublic2(String paramString)
    throws 
  {
    try
    {
      this.h.invoke(this, m4, new Object[] { paramString });
      return;
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

  public final void methodPublic1()
    throws 
  {
    try
    {
      this.h.invoke(this, m3, null);
      return;
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

  public final String toString()
    throws 
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m5 = Class.forName("proxy.UserInterface").getMethod("defaultMethod1", new Class[] { Integer.TYPE });
      m6 = Class.forName("proxy.UserInterface").getMethod("defaultMethod2", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      m4 = Class.forName("proxy.UserInterface").getMethod("methodPublic2", new Class[] { Class.forName("java.lang.String") });
      m3 = Class.forName("proxy.UserInterface").getMethod("methodPublic1", 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());
  }
}

这就是最终真正的代理类,它继承自Proxy并实现了我们定义的UserInterface接口

也就是说:

UserInterface proxy =(UserInterface)Proxy.newProxyInstance(loader, interfaces,
					handler);

这里的proxy实际是这个类的一个实例,那么我们调用它的:

proxy.methodPublic1();

就是调用我们定义的TestInvocationHandler的 invoke方法:

m3

m3 = Class.forName("proxy.UserInterface").getMethod("methodPublic1", new Class[0]);

所以呢,真正的代理是JDK动态生成的它继承自Proxy并实现了我们定义的UserInterface接口,在实现UserInterface接口方法的内部,通过反射调用了TestInvocationHandler的invoke方法。

编辑于 2018-03-27