JAVA 动态代理(proxy)的实现和源码分析
2016-07-10 22:11
936 查看
JDK动态代理(proxy)可以在运行时创建一个实现一组给定接口的新类。但是略有限制,即被代理的类必须实现某个接口,否则无法使用JDK自带的动态代理,因此,如果不满足条件,就只能使用另一种更加灵活,功能更加强大的动态代理技术—— CGLIB。Spring里会自动在JDK的代理和CGLIB之间切换,同时我们也可以强制Spring使用CGLIB。
闲话少说,下面先用实例介绍使用方式,接着从proxy类源码角度分析实现过程:
public class TranceHander implements InvocationHandler{
private Object tObject;
public TranceHander(Object t){
tObject=t;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
System.out.println("被代理对象:"+tObject);
System.out.println("方法:"+method.getName());
return method.invoke(tObject,args);//方法反射
}
}
(2)使用Proxy类的newProxyInstance方法创建代理对象或getProxyClass方法获得代理类Class。
测试mian方法中,写了一个代理类,从1-1000的整数数组中使用二分查找随机查找一个整数,实现对象比较和toString接口代理
public class ProxyTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Object[] elements=new Object[1000];
for(int i=0;i<elements.length;i++){
Integer value=i+1;//被代理对象
InvocationHandler handler=new TranceHander(value);//构建调度处理器
Object proxy=Proxy.newProxyInstance(null, new Class[]{Comparable.class}, handler);
elements[i]=proxy;
}
Integer key=new Random().nextInt(1000)+1;
int res=Arrays.binarySearch(elements, key);
if(res>=0){
System.out.println(elements[res].toString());
}
System.out.println("查找Key:"+key);
}
}
运行结果:
到这里我们得思考:
1. 这个代理对象是由谁且怎么生成的?
2. invoke方法是怎么调用的?
3. invoke和add方法有什么对应关系?
4. 生成的代理对象是什么样子的?
下面我引入了OPEN JDK源码点击打开链接 ,查看了一下午,终于看明白了
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/laugh.gif)
。
(1)代理对象生成:
(2)查看Proxy类的newProxyInstance方法
从生成对象方法中,我们看到三个关键的地方:
Class<?> cl = getProxyClass0(loader, interfaces);//得到代理类
final Constructor<?> cons = cl.getConstructor(constructorParams);
newInstance(cons, ih);//将InvocationHandler h传入代理对象中
(3)生成Proxy类,查看getProxyClass0方法,
这个方法有点长,抽取关键的地方:
1.先抽取被代理类实现的接口Interface,检测是否符合要求
2.查看代理对象缓存中是否有我们要创建的代理类,如果有,直接获取;没有则创建
如果有则: return proxyClassCache.get(loader, interfaces);
没有则创建,先定义代理类的包名,如果所有的接口都是公共的,则默认将创建的类放在String PROXY_PACKAGE = "com.sun.proxy";中,若果存在
非public接口则所有的非public接口必须在同一包下,代理类也放在此包下,否则系统抛异常。
接下来创建类,和将字节码写入类文件中:
(4)创建代理实例,将
newInstance(cons, ih);//将InvocationHandler h传入代理对象中
看完源码,我还是有点困惑,直到我看到生成的代理类文件源码后,豁然开朗。其实主要一步就在于生成类
的过程,类文件中建立被代理对象接口的invoke调用,话不多说看源码(我直接在测试用例调用的ProxyGenerator.generateProxyClass( proxyName, interfaces)接口生成的)
接着看class文件的反编译源码吧,看大家都明白了吧,直接用的Method的反射机制实现的代理,equal、hascode、toString方法是所有类都有的,compareTo则是被代理对象的实现接口:
闲话少说,下面先用实例介绍使用方式,接着从proxy类源码角度分析实现过程:
1.JDK动态代理实例
(1)动态代理首先提供一个调度处理器接口(Invocationhandler),该接口实例封装了我们要代理的对象实例的数据。public class TranceHander implements InvocationHandler{
private Object tObject;
public TranceHander(Object t){
tObject=t;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
System.out.println("被代理对象:"+tObject);
System.out.println("方法:"+method.getName());
return method.invoke(tObject,args);//方法反射
}
}
(2)使用Proxy类的newProxyInstance方法创建代理对象或getProxyClass方法获得代理类Class。
测试mian方法中,写了一个代理类,从1-1000的整数数组中使用二分查找随机查找一个整数,实现对象比较和toString接口代理
public class ProxyTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Object[] elements=new Object[1000];
for(int i=0;i<elements.length;i++){
Integer value=i+1;//被代理对象
InvocationHandler handler=new TranceHander(value);//构建调度处理器
Object proxy=Proxy.newProxyInstance(null, new Class[]{Comparable.class}, handler);
elements[i]=proxy;
}
Integer key=new Random().nextInt(1000)+1;
int res=Arrays.binarySearch(elements, key);
if(res>=0){
System.out.println(elements[res].toString());
}
System.out.println("查找Key:"+key);
}
}
运行结果:
2.JDK源码实现原理分析
到这里我们发现,我们使用代理对象调用接口时候均调用TranceHander对象的invoker方法,使用Method的类的反射机制执行被代理对象的实现接口方法。到这里我们得思考:
1. 这个代理对象是由谁且怎么生成的?
2. invoke方法是怎么调用的?
3. invoke和add方法有什么对应关系?
4. 生成的代理对象是什么样子的?
下面我引入了OPEN JDK源码点击打开链接 ,查看了一下午,终于看明白了
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/laugh.gif)
。
(1)代理对象生成:
Object proxy=Proxy.newProxyInstance(null, new Class[]{Comparable.class}, handler);
(2)查看Proxy类的newProxyInstance方法
从生成对象方法中,我们看到三个关键的地方:
Class<?> cl = getProxyClass0(loader, interfaces);//得到代理类
final Constructor<?> cons = cl.getConstructor(constructorParams);
newInstance(cons, ih);//将InvocationHandler h传入代理对象中
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { if (h == null) { throw new NullPointerException(); } final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, interfaces); } /* * Look up or generate the designated proxy class. */ Class<?> cl = getProxyClass0(loader, interfaces); /* * Invoke its constructor with the designated invocation handler. */ try { 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 { return newInstance(cons, ih); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); } }
(3)生成Proxy类,查看getProxyClass0方法,
这个方法有点长,抽取关键的地方:
1.先抽取被代理类实现的接口Interface,检测是否符合要求
/* collect interface names to use as key for proxy class cache */ String[] interfaceNames = new String[interfaces.length]; // for detecting duplicates Set<Class<?>> interfaceSet = new HashSet<>(); for (int i = 0; i < interfaces.length; i++) { /* * Verify that the class loader resolves the name of this * interface to the same Class object. */ String interfaceName = interfaces[i].getName(); Class<?> interfaceClass = null; try { interfaceClass = Class.forName(interfaceName, false, loader); } catch (ClassNotFoundException e) { } if (interfaceClass != interfaces[i]) { throw new IllegalArgumentException( interfaces[i] + " is not visible from class loader"); } /* * Verify that the Class object actually represents an * interface. */ if (!interfaceClass.isInterface()) { throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface"); } /* * Verify that this interface is not a duplicate. */ if (interfaceSet.contains(interfaceClass)) { throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName()); } interfaceSet.add(interfaceClass); interfaceNames[i] = interfaceName; }
2.查看代理对象缓存中是否有我们要创建的代理类,如果有,直接获取;没有则创建
如果有则: return proxyClassCache.get(loader, interfaces);
没有则创建,先定义代理类的包名,如果所有的接口都是公共的,则默认将创建的类放在String PROXY_PACKAGE = "com.sun.proxy";中,若果存在
非public接口则所有的非public接口必须在同一包下,代理类也放在此包下,否则系统抛异常。
<span style="white-space:pre"> </span> for (int i = 0; i < interfaces.length; i++) { int flags = interfaces[i].getModifiers(); if (!Modifier.isPublic(flags)) { String name = interfaces[i].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) { // if no non-public proxy interfaces, use com.sun.proxy package proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; }
接下来创建类,和将字节码写入类文件中:
byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces); proxyClass = defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length); return proxyClass;
(4)创建代理实例,将
newInstance(cons, ih);//将InvocationHandler h传入代理对象中
看完源码,我还是有点困惑,直到我看到生成的代理类文件源码后,豁然开朗。其实主要一步就在于生成类
的过程,类文件中建立被代理对象接口的invoke调用,话不多说看源码(我直接在测试用例调用的ProxyGenerator.generateProxyClass( proxyName, interfaces)接口生成的)
public static void main(String[] args) { // TODO Auto-generated method stub Integer value=1; InvocationHandler handler=new TranceHander(value);//构建调度处理器 Object proxy=Proxy.newProxyInstance(null, Integer.class.getInterfaces(), handler); String path = "D://aaa.class"; byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0",Integer.class.getInterfaces()); FileOutputStream out = null; try { out = new FileOutputStream(path); out.write(classFile); out.flush(); } catch (Exception e) { e.printStackTrace(); } finally { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } }
接着看class文件的反编译源码吧,看大家都明白了吧,直接用的Method的反射机制实现的代理,equal、hascode、toString方法是所有类都有的,compareTo则是被代理对象的实现接口:
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 Comparable { private static Method m3; private static Method m1; private static Method m0; private static Method m2; public $Proxy0(InvocationHandler paramInvocationHandler) throws { super(paramInvocationHandler); } public final int compareTo(Object paramObject) throws { try { return ((Integer)this.h.invoke(this, m3, new Object[] { paramObject })).intValue(); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } 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 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 { m3 = Class.forName("java.lang.Comparable").getMethod("compareTo", new Class[] { Class.forName("java.lang.Object") }); 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]); 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()); } } }
相关文章推荐
- 早前学习Java记录
- java学习之七(IO流下篇)
- 4、接口与内部类
- java文件的拷贝
- Eclipse-调试
- JAVA设计模式(02):创建型-抽象工厂模式(Abstract Factory)
- java代理机制
- java非数据库自增的主键
- 三、java三大特性--多态
- java环境配置
- java Web表示层技术
- java Web表示层技术
- 迷你DVD java
- MVP+Retrofit2+RxJava使用方法demo
- java.lang.ClassNotFoundException
- spring(java,js,html) 截图上传
- Spring (三)配置文件详解
- Java 之多线程同步
- java.lang.SecurityException: Permission denied (missing INTERNET permission?) 解决
- 疯狂JAVA讲义比较--JAVA概述