JDK Proxy 解析----基于Java 8

Java中从1.3中引入Proxy,实现接口的动态代理。JDK的动态代理,就是在程序运行的过程中,根据被代理的接口来动态生成代理类的class文件,并加载运行的过程。本文从简单例子入手,通过分析源码看看其内部实现原理,使用的是JDK 1.8。 ####简单运用 使用动态代理主要涉及接口InvocationHandler,以及Proxy类。 通过动态代理实现对接口中方法调用前后进行拦截处理

创建要代理的接口,以及一个实现类。

package com.proxy;

/**
 * 
 * 要代理的接口<br/>
 * 
 * @version
 */
public interface PeopleService {
    public void sayHello();

    public void printName(String name);
}

简单实现类EnglishService

package com.proxy;

/**
 * 
 * 注释内容<br/>
 * 
 * 
 * @version
 */
public class EnglishService implements PeopleService {
    @Override
    public void sayHello() {
        System.out.println("Hi~");
    }
    
    @Override
    public void printName(String name) {
        System.err.println("Your name:" + name);
    }
}

定义自己的InvocationHandler

package com.proxy;

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

/**
 * 
 * 注释内容<br/>
 * 
 * @version
 */
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 {
        //调用前打印
        System.err.println("------begin----------");
        method.invoke(target, args);
        System.err.println("------end----------");
        return null;
    }
}

编写测试类

package com.test;

import java.lang.reflect.Proxy;

import org.testng.annotations.Test;

import com.proxy.EnglishService;
import com.proxy.MyInvocationHandler;
import com.proxy.PeopleService;

public class MyTest {

    @Test
    public void proxyTest() {
        MyInvocationHandler handler = new MyInvocationHandler(new EnglishService());
        PeopleService proxyService = (PeopleService) Proxy.newProxyInstance(MyTest.class.getClassLoader(), new Class[] { PeopleService.class }, handler);
        proxyService.sayHello();
    }
}

运行结果:

这里写图片描述 成功实现对接口方法的前后拦截。JDK内部究竟怎么实现代理的?什么时候调用MyInvocationHandler 的invoke方法?下面分析原理: 看代理类获取时,关键代码为Proxy.newProxyInstance,源码:

@CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

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

        /*
         * 代理类生成的核心代码
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * 通过传入的InvocationHander调用其构造器获取接口实例
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
	
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            //非公开接口的处理
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

查看getProxyClass0方法:

   //生成一个代理类,在调用该方法前,必须调用checkProxyAccess校验权限
    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
         //代理接口数限制          
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        //如果由给定的加载器实现给定的接口定义的代理类存在,返回缓存;否则,它将通过ProxyClassFactory创建代理类
        return proxyClassCache.get(loader, interfaces);
    }

这里只是用WeakCache做了proxy classes缓存:

private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

通过KeyFactory和ProxyClassFactory作为WeakCache的键和值,它们都是Proxy的内部静态类,都实现了BiFunction接口。继续查看WeakCache的get方法可看到,proxy class的生成最终调用了ProxyClassFactory的apply方法。关于WeakCache实现缓存的代码这里不多做描述。下面重点看ProxyClassFactory的定义和appy方法的实现:

    //通过ClassLoader和接口列表,生成和定义一个proxy class
    private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
        // 所有代理类的命名前缀
        private static final String proxyClassNamePrefix = "$Proxy";

        // 一个唯一的number作为proxy class的名称标识
        private static final AtomicLong nextUniqueNumber = new AtomicLong();
        //proxy class生成方法
        @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class<?> intf : interfaces) {
                 //确认类加载器解析了这个名字的接口到相同的Class对象。
                Class<?> interfaceClass = null;
                try {
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
                if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }
                //确认代理的Class是接口,从这可看出JDK动态代理的劣势
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }
                //接口重复校验
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
                }
            }

            String proxyPkg = null;     // 定义proxy class 所在的包
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

            //记录所有non-public的 proxy interfaces都在同一个package中
            for (Class<?> intf : interfaces) {
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {
                    accessFlags = Modifier.FINAL;
                    String name = intf.getName();
                    int n = name.lastIndexOf('.');
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                            "non-public interfaces from different packages");
                    }
                }
            }

            if (proxyPkg == null) {
                // 如果没有non-public的interfaces,默认包为com.sun.proxy
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }

            /*
             * Choose a name for the proxy class to generate.
             */
            long num = nextUniqueNumber.getAndIncrement();
            //最终大概名字为:com.sun.proxy.$Proxy1
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            /*
             * 生成特殊的proxy class.
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                /*
                 * A ClassFormatError here means that (barring bugs in the
                 * proxy class generation code) there was some other
                 * invalid aspect of the arguments supplied to the proxy
                 * class creation (such as virtual machine limitations
                 * exceeded).
                 */
                throw new IllegalArgumentException(e.toString());
            }
        }
    }

调用ProxyGenerator.generateProxyClass生成proxy class, ProxyGenerator在sun.misc包中,未提供源码,我们通过反编译可以看到:


public static byte[] generateProxyClass(String arg, Class<?>[] arg0, int arg1) {
      ProxyGenerator arg2 = new ProxyGenerator(arg, arg0, arg1);
      byte[] arg3 = arg2.generateClassFile();
      if(saveGeneratedFiles) {
         AccessController.doPrivileged(new 1(arg, arg3));
      }

      return arg3;
   }
   //私有构造器
   private ProxyGenerator(String arg0, Class<?>[] arg1, int arg2) {
		this.className = arg0;
		this.interfaces = arg1;
		this.accessFlags = arg2;
	}
	

下面是generateClassFile方法:

	private byte[] generateClassFile() {
	      //添加从 Object基类中继承的方法
		this.addProxyMethod(hashCodeMethod, Object.class);
		this.addProxyMethod(equalsMethod, Object.class);
		this.addProxyMethod(toStringMethod, Object.class);
		//添加接口中的方法实现
		Class[] arg0 = this.interfaces;
		int arg1 = arg0.length;

		int arg2;
		Class arg3;
		for (arg2 = 0; arg2 < arg1; ++arg2) {
			arg3 = arg0[arg2];
			Method[] arg4 = arg3.getMethods();
			int arg5 = arg4.length;

			for (int arg6 = 0; arg6 < arg5; ++arg6) {
				Method arg7 = arg4[arg6];
				this.addProxyMethod(arg7, arg3);
			}
		}

		Iterator arg10 = this.proxyMethods.values().iterator();

		List arg11;
		while (arg10.hasNext()) {
			arg11 = (List) arg10.next();
			checkReturnTypes(arg11);
		}

		Iterator arg14;
		try {
		        //构造方法
			this.methods.add(this.generateConstructor());
			arg10 = this.proxyMethods.values().iterator();

			while (arg10.hasNext()) {
				arg11 = (List) arg10.next();
				arg14 = arg11.iterator();

				while (arg14.hasNext()) {
					ProxyMethod arg15 = (ProxyMethod) arg14.next();
					this.fields.add(new FieldInfo(this, arg15.methodFieldName, "Ljava/lang/reflect/Method;", 10));
					this.methods.add(ProxyMethod.access$100(arg15));
				}
			}

			this.methods.add(this.generateStaticInitializer());
		} catch (IOException arg9) {
			throw new InternalError("unexpected I/O Exception", arg9);
		}

		if (this.methods.size() > '') {
			throw new IllegalArgumentException("method limit exceeded");
		} else if (this.fields.size() > '') {
			throw new IllegalArgumentException("field limit exceeded");
		} else {
			this.cp.getClass(dotToSlash(this.className));
			this.cp.getClass("java/lang/reflect/Proxy");
			arg0 = this.interfaces;
			arg1 = arg0.length;

			for (arg2 = 0; arg2 < arg1; ++arg2) {
				arg3 = arg0[arg2];
				this.cp.getClass(dotToSlash(arg3.getName()));
			}

			this.cp.setReadOnly();
			//生成文件
			ByteArrayOutputStream arg12 = new ByteArrayOutputStream();
			DataOutputStream arg13 = new DataOutputStream(arg12);

			try {
				arg13.writeInt(-889275714);
				arg13.writeShort(0);
				arg13.writeShort(49);
				this.cp.write(arg13);
				arg13.writeShort(this.accessFlags);
				arg13.writeShort(this.cp.getClass(dotToSlash(this.className)));
				arg13.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
				arg13.writeShort(this.interfaces.length);
				Class[] arg16 = this.interfaces;
				int arg17 = arg16.length;

				for (int arg18 = 0; arg18 < arg17; ++arg18) {
					Class arg21 = arg16[arg18];
					arg13.writeShort(this.cp.getClass(dotToSlash(arg21.getName())));
				}

				arg13.writeShort(this.fields.size());
				arg14 = this.fields.iterator();

				while (arg14.hasNext()) {
					FieldInfo arg19 = (FieldInfo) arg14.next();
					arg19.write(arg13);
				}

				arg13.writeShort(this.methods.size());
				arg14 = this.methods.iterator();

				while (arg14.hasNext()) {
					MethodInfo arg20 = (MethodInfo) arg14.next();
					arg20.write(arg13);
				}

				arg13.writeShort(0);
				//返回字节流
				return arg12.toByteArray();
			} catch (IOException arg8) {
				throw new InternalError("unexpected I/O Exception", arg8);
			}
		}
	}

看到这,我们可以很清晰的知道Proxy class是在什么时候生成的,以及这个class的大概面目(有Object的基本hashCode、equals、toString方法;有构造方法,有接口的实现方法)。我们回到generateProxyClass方法,看到生成后处理(上面有代码,不做重复):对saveGeneratedFiles进行判断,为真的话进行AccessController.doPrivileged(new 1(arg, arg3)),查看资料是将生成的proxy class文件存在硬盘,未测试,不做说明。其中saveGeneratedFiles是一个系统变量,可以通过 System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");进行设置,默认false。

private static final boolean saveGeneratedFiles = ((Boolean) AccessController
			.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"))).booleanValue();
	

知道调用原理,我们可以使用ProxyGenerator.generateProxyClass生成文件看看具体内容,编写测试方法:

public static void main(String[] args) {
        String fileName = "$Proxy11";
        // 获取代理类的字节码  
        byte[] classFile = ProxyGenerator.generateProxyClass(fileName, EnglishService.class.getInterfaces());
        FileOutputStream out = null;
        String outFilePath = "yourpath" + fileName + ".class";
        try {
            out = new FileOutputStream(outFilePath);
            out.write(classFile);
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

最后在指定路径下生成$Proxy11.class文件,反编译查看内容:

import com.proxy.api.PeopleService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
/**
 * 生成的类继承了Proxy,实现了要代理的接口PeopleService
 *
 */
public final class $Proxy11
  extends Proxy
  implements PeopleService
{
  private static Method m1;
  private static Method m3;
  private static Method m2;
  private static Method m4;
  private static Method m0;
  
  public $proxy11(InvocationHandler paramInvocationHandler)
  {
    //调用基类Proxy的构造器
    super(paramInvocationHandler);
  }
  
  public final boolean equals(Object paramObject)
  {
    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 sayHello()
  {
    try
    {
      this.h.invoke(this, m3, null);
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final String toString()
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final void printName(String paramString)
  {
    try
    {
      this.h.invoke(this, m4, new Object[] { paramString });
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final int hashCode()
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  static
  {
    try
    {
    //利用反射生成5个方法,包括Object中的equals、toString、hashCode以及PeopleService中的sayHello和printName
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("com.proxy.api.PeopleService").getMethod("sayHello", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m4 = Class.forName("com.proxy.api.PeopleService").getMethod("printName", new Class[] { Class.forName("java.lang.String") });
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}

java.lang.reflect中Proxy有以下代码:

    /**
     * the invocation handler for this proxy instance.
     * @serial
     */
     //直接子类可使用
    protected InvocationHandler h;

   /**
     * Constructs a new {@code Proxy} instance from a subclass
     * (typically, a dynamic proxy class) with the specified value
     * for its invocation handler.
     *
     * @param  h the invocation handler for this proxy instance
     *
     * @throws NullPointerException if the given invocation handler, {@code h},
     *         is {@code null}.
     */
     //直接子类可调用
    protected Proxy(InvocationHandler h) {
        Objects.requireNonNull(h);
        this.h = h;
    }

现在再看生成的$Proxy11.class反编译的java代码中,调用sayHello时会this.h.invoke(this, m3, null);调用Proxy类中InvocationHandler的invoke方法,所以,文章开头我们的小例子中:

PeopleService proxyService = (PeopleService) Proxy.newProxyInstance(MyTest.class.getClassLoader(), new Class[] { PeopleService.class }, handler);
        proxyService.sayHello();

proxyService.sayHello()的结果是走的MyInvocationHandler的invoke方法,也就一目了然。

总结

因为生成的proxy class中,继承了Proxy类,实现了需要代理的接口,而Java中是单继承,多实现的处理方式,也就解释了JDK动态代理中只能代理接口的原因了。

注意

关于通过设置 System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); 环境变量使得proxy class生成文件存在disk中,我未测试通过,对这一块,持保留意见

参考

特别感谢以下网友博客提供的帮助: http://rejoy.iteye.com/blog/1627405 http://blog.csdn.net/mhmyqn/article/details/48474815

转载于:https://my.oschina.net/u/2264912/blog/1592613

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值