java -- java.lang.reflect.proxy分析
2016-06-13 17:17
471 查看
proxy使用
实例1
实例2
简述
应用场景
分析javalangreflectProxy
静态方法
源码
org.springframework.aop.framework.CglibAopProxy
org.springframework.aop.framework.JdkDynamicAopProxy
两种动态代理的实现。
方法
看这行代码
点进去,发现是一个接口
实现类
用到了
详见:
关键代码
源码
下面这段源码属于sun包下的,oracle并没有开放源码,我在下面网址收到的源码:http://www.docjar.com/html/api/sun/misc/ProxyGenerator.java.html,生成代理类的class文件
这块代码使用native修饰,具体实现不是使用java编写,应该是在jvm中使用c编写的。
所有的代码生成的工作都由神秘的ProxyGenerator所完成了,当你尝试去探索这个类时,你所能获得的信息仅仅是它位于并未公开的sun.misc包,有若干常量、变量和方法以完成这个神奇的代码生成的过程,但是sun并没有提供源代码以供研读。至于动态类的定义,则由Proxy的native静态方法defineClass0执行。
网上找到一块代码,使用C++实现的defineClass0方法
实例1
实例2
简述
应用场景
分析javalangreflectProxy
静态方法
源码
proxy使用
实例1
http://www.cnblogs.com/linjiqin/archive/2011/02/18/1957600.html实例2
/* *Copyright (c) 2016, gp.inc and/or its affiliates. All rights reserved. */ package com.proxy.demo2; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; public class ProxyStudy { @SuppressWarnings("all") public static void main(String[] args) throws Exception { ClassLoader loader = Collection.class.getClassLoader(); Class<?>[] interfaces = new Class[] { Collection.class }; InvocationHandler h = new InvocationHandler() { // proxyBuildColl是对ArrayList进行代理 ArrayList target = new ArrayList(); public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(method.getName() + "执行之前..."); if (null != args) { System.out.println("方法的参数:" + Arrays.asList(args)); } else { System.out.println("方法的参数:" + null); } Object result = method.invoke(target, args); System.out.println(method.getName() + "执行之后..."); return result; } }; Collection proxyBuildCollection2 = (Collection) Proxy.newProxyInstance(loader, interfaces, h); proxyBuildCollection2.add("abc"); proxyBuildCollection2.size(); proxyBuildCollection2.clear(); proxyBuildCollection2.getClass().getName(); } }
简述
动态代理,代理一个对象,间接执行相关操作,并且在执行操作前后可以增加额外操作,如日志。应用场景
spring框架AOP中核心采用动态代理org.springframework.aop.framework.CglibAopProxy
org.springframework.aop.framework.JdkDynamicAopProxy
两种动态代理的实现。
分析java.lang.reflect.Proxy
静态方法
方法
newProxyInstance是我们经常用到的,返回目标对象。
Collection proxyBuildCollection2 = (Collection) Proxy.newProxyInstance(loader, interfaces, h);
源码
@CallerSensitive 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); } /* * Look up or generate the designated proxy class. */ Class<?> cl = getProxyClass0(loader, intfs); /* * 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()); } }
看这行代码
Class<?> cl = getProxyClass0(loader, intfs);
private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) { if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } // If the proxy class defined by the given loader implementing // the given interfaces exists, this will simply return the cached copy; // otherwise, it will create the proxy class via the ProxyClassFactory return proxyClassCache.get(loader, interfaces); }
proxyClassCache.get(loader, interfaces);这行代码返回类对象
public V get(K key, P parameter) { Objects.requireNonNull(parameter); expungeStaleEntries(); Object cacheKey = CacheKey.valueOf(key, refQueue); // lazily install the 2nd level valuesMap for the particular cacheKey ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey); if (valuesMap == null) { ConcurrentMap<Object, Supplier<V>> oldValuesMap = map.putIfAbsent(cacheKey, valuesMap = new ConcurrentHashMap<>()); if (oldValuesMap != null) { valuesMap = oldValuesMap; } } // create subKey and retrieve the possible Supplier<V> stored by that // subKey from valuesMap Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); Supplier<V> supplier = valuesMap.get(subKey); Factory factory = null; while (true) { if (supplier != null) { // supplier might be a Factory or a CacheValue<V> instance V value = supplier.get(); if (value != null) { return value; } } // else no supplier in cache // or a supplier that returned null (could be a cleared CacheValue // or a Factory that wasn't successful in installing the CacheValue) // lazily construct a Factory if (factory == null) { factory = new Factory(key, parameter, subKey, valuesMap); } if (supplier == null) { supplier = valuesMap.putIfAbsent(subKey, factory); if (supplier == null) { // successfully installed Factory supplier = factory; } // else retry with winning supplier } else { if (valuesMap.replace(subKey, supplier, factory)) { // successfully replaced // cleared CacheEntry / unsuccessful Factory // with our Factory supplier = factory; } else { // retry with current supplier supplier = valuesMap.get(subKey); } } } }
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));这行代码核心。
点进去,发现是一个接口
interface BiFunction<T, U, R> { /** * Applies this function to the given arguments. * * @param t the first function argument * @param u the second function argument * @return the function result */ R apply(T t, U u); }
实现类
用到了
ProxyClassFactory类
详见:
private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
ProxyClassFactory源码
private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> { // prefix for all proxy class names private static final String proxyClassNamePrefix = "$Proxy"; // next number to use for generation of unique proxy class names private static final AtomicLong nextUniqueNumber = new AtomicLong(); @Override public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) { Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); for (Class<?> intf : interfaces) { /* * Verify that the class loader resolves the name of this * interface to the same Class object. */ 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"); } /* * 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.put(interfaceClass, Boolean.TRUE) != null) { throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName()); } } String proxyPkg = null; // package to define proxy class in /* * Record the package of a non-public proxy interface so that the * proxy class will be defined in the same package. Verify that * all non-public proxy interfaces are in the same package. */ for (Class<?> intf : interfaces) { int flags = intf.getModifiers(); if (!Modifier.isPublic(flags)) { 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) { // if no non-public proxy interfaces, use com.sun.proxy package proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; } /* * Choose a name for the proxy class to generate. */ long num = nextUniqueNumber.getAndIncrement(); String proxyName = proxyPkg + proxyClassNamePrefix + num; /* * Generate the specified proxy class. */ byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces); 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()); } } }
关键代码
byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces);
源码
下面这段源码属于sun包下的,oracle并没有开放源码,我在下面网址收到的源码:http://www.docjar.com/html/api/sun/misc/ProxyGenerator.java.html,生成代理类的class文件
public static byte[] generateProxyClass(final String name, Class[] interfaces) { ProxyGenerator gen = new ProxyGenerator(name, interfaces); final byte[] classFile = gen.generateClassFile(); if (saveGeneratedFiles) { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<Void>() { public Void run() { try { FileOutputStream file = new FileOutputStream(dotToSlash(name) + ".class"); file.write(classFile); file.close(); return null; } catch (IOException e) { throw new InternalError( "I/O exception saving generated file: " + e); } } }); } return classFile; }
private static native Class defineClass0(ClassLoader loader, String name, byte[] b, int off, int len);
这块代码使用native修饰,具体实现不是使用java编写,应该是在jvm中使用c编写的。
所有的代码生成的工作都由神秘的ProxyGenerator所完成了,当你尝试去探索这个类时,你所能获得的信息仅仅是它位于并未公开的sun.misc包,有若干常量、变量和方法以完成这个神奇的代码生成的过程,但是sun并没有提供源代码以供研读。至于动态类的定义,则由Proxy的native静态方法defineClass0执行。
网上找到一块代码,使用C++实现的defineClass0方法
/* * Clasbs: com_test_start_CommonClassLoader * Method: defineClass0 * Signature: (Ljava/lang/String;[BII)Ljava/lang/Class; */ JNIEXPORT jclass JNICALL Java_com_test_start_CommonClassLoader_defineClass0 (JNIEnv *env, jobject loader, jstring name, jbyteArray buffer, jint start, jint len) { jbyteArray temp=env->NewByteArray(len);//new一个数组,并申请一块内存 arraycopy(env,buffer,start,temp,start,len);//数组的复制相当于System.copy()方法 jbyteArray byte0=encrypt(env,temp,len);//进行class文件的解密操作 if(byte0==NULL) { env->DeleteLocalRef(temp);//释放内存 return NULL; } jsize size=env->GetArrayLength(byte0);//技术数组的长度相当于Array的length属性 jclass classLoader=env->GetSuperclass(env->GetSuperclass(env->GetSuperclass(env->GetObjectClass(loader))));//获取父类装载器 jmethodID mid=env->GetMethodID(classLoader,"defineClass","(Ljava/lang/String;[BII)Ljava/lang/Class;");//获取defineClass方法 defineClass jclass cls=(jclass)env->CallObjectMethod(loader,mid,name,byte0,start,size);//调用Classloader的defineClass定义一个类到jvm中 env->DeleteLocalRef(byte0);//释放内存 return cls; }
相关文章推荐
- java poi技术操作excel之读取Excel
- Servlet+JSP+JavaBean开发模式(MVC)介绍
- Java加密技术(五)——非对称加密算法的由来DH
- spring security (五)Filter
- SwaggerUI+SpringMVC——构建RestFulAPI的可视化界面
- java关键字volatile
- 使用Java的设备列表(很全面)
- struts异常声明机制的实现和原理
- eclipse maven run as on server src/main
- Java LinkedList 源码剖析
- Java加密技术(三)——PBE算法
- JAVA中的Fork/Join框架
- 关于Java中Byte类型的取值范围是-128~127的理解
- Java加密技术(二)——对称加密算法DES&AES
- Java之内存诊断
- Spring Boot 实践折腾记(四):配置即使用,常用配置
- 在eclipse里使用sun.net连接FTP服务器
- Java Jersey2使用总结
- Java加密技术(一)——BASE64与单向加密算法MD5&SHA&MAC
- cannot create inner bean while setting constructor argument