动态调用方法,大多数情况下,只能使用反射机制实现。反射性能上远远逊于直接调用(虽然JDK7中的MethodHandle也可以稍微提高动态调用性能,但JDK7在企业应用中暂时还无法普及)。
反射调用之所以性能低下,主要是因为通用接口对参数进行数组封装和解封导致,而大多数情况下,反射调用时的参数数量和类型,我们是知道的。那么,能不能动态调用方法时不去对参数进行封装和解封,从而达到提高动态调用的效果呢?
基于此理念,实现了Invokers类。使用该类时,先行定义好调用接口,调用接口包含了需要反射调用的方法的参数列表以及返回值的接口方法(方法名可以和反射方法名不一致,且参数列表的第一个参数是反射调用的对象,其它参数才是反射调用时需要的参数)。接口定义好之后,可以通过Invokers生成该接口的实例,然后通过该实例来实现动态调用。例子如下:
上面的单元测试中,分别通过不同方式调用一亿次Date类型的getTime和setTime方法,输出如下:
time=1362806708572
time1=33333333
time2=33333333
直接调用耗时:18ms
Invokers调用耗时:120ms
JDK反射调用耗时:5352ms
FastMethod调用耗时:5057ms
可见Invokes的性能和直接调用已经接近了(实际上,如果接口处声明为准确参数类型而不是通用类型的话,会和直接调用性能一样),和传统反射相比相差两个数量级。
注:测试机器是Macbook Pro 374,虚拟机是JDK 6。
另一个例子,实现传统的通用反射接口(性能也是最好的)。测试代码如下:
输出结果如下(和上面的单元测试一样的环境):
1362857121037
333333
Invoker调用耗时:131ms
JDK反射调用耗时:5106ms
CGLIB反射调用耗时:4610ms
Invokers的代码如下(需javassist支持,asm生成字节码太麻烦 ):
以Invokers为基础,自己实现了一个BeanMap,代码如下:
算上创建时间的话,比cglib的BeanMap快得多。但是如果仅仅是执行get或者put方法,则还是稍慢于cglib的BeanMap(大约是cglib的BeanMap所耗时间的1.5倍左右),因为cglib内部字节码生成的Map是使用switch定位key的,这比HashMap还要快,无能为力了 。但常规使用下,经常是对新对象创建Map并且只需要遍历执行一次get/put,所以创建时间慢的话还是严重影响性能的,使用此BeanMap在创建上速度是cglib的10倍以上。很多开源库都依赖于BeanMap,如JSON解析等等,如能使用此API,相信相关库的性能也会跟着大幅提升。
反射调用之所以性能低下,主要是因为通用接口对参数进行数组封装和解封导致,而大多数情况下,反射调用时的参数数量和类型,我们是知道的。那么,能不能动态调用方法时不去对参数进行封装和解封,从而达到提高动态调用的效果呢?
基于此理念,实现了Invokers类。使用该类时,先行定义好调用接口,调用接口包含了需要反射调用的方法的参数列表以及返回值的接口方法(方法名可以和反射方法名不一致,且参数列表的第一个参数是反射调用的对象,其它参数才是反射调用时需要的参数)。接口定义好之后,可以通过Invokers生成该接口的实例,然后通过该实例来实现动态调用。例子如下:
public static interface Getter { Object get(Object obj); } public static interface Setter { void set(Object obj, Object value); } @Test public void testInvoke() { try { // 创建getter调用器,用于调用getTime方法 Getter getter = Invokers.newInvoker(Getter.class, Date.class, "getTime", null, Long.TYPE); // 创建setter调用器,用于调用setTime方法 Setter setter = Invokers.newInvoker(Setter.class, Date.class, "setTime", new Class<?>[] { Long.TYPE }, null); Date date = new Date(); System.out.println("time=" + getter.get(date)); setter.set(date, 33333333L); System.out.println("time1=" + getter.get(date)); Method getTime = Date.class.getMethod("getTime"); Method setTime = Date.class.getMethod("setTime", Long.TYPE); getTime.setAccessible(true); setTime.setAccessible(true); FastClass fastClass = FastClass.create(Date.class); FastMethod fastGetTime = fastClass.getMethod(getTime); FastMethod fastSetTime = fastClass.getMethod(setTime); System.out.println("time2=" + getTime.invoke(date)); long t = System.currentTimeMillis(); for (int i = 0; i < 100000000; i++) { date.setTime(33333333L); date.getTime(); } long t1 = System.currentTimeMillis(); System.out.println("直接调用耗时:" + (t1 - t) + "ms"); t1 = System.currentTimeMillis(); for (int i = 0; i < 100000000; i++) { setter.set(date, 33333333L); getter.get(date); } long t2 = System.currentTimeMillis(); System.out.println("Invokers调用耗时:" + (t2 - t1) + "ms"); t2 = System.currentTimeMillis(); for (int i = 0; i < 100000000; i++) { setTime.invoke(date, 6666666L); getTime.invoke(date); } long t3 = System.currentTimeMillis(); System.out.println("JDK反射调用耗时:" + (t3 - t2) + "ms"); t3 = System.currentTimeMillis(); for (int i = 0; i < 100000000; i++) { fastSetTime.invoke(date, new Object[] { 6666666L }); fastGetTime.invoke(date, new Object[] {}); } long t4 = System.currentTimeMillis(); System.out.println("FastMethod调用耗时:" + (t4 - t3) + "ms"); } catch (Throwable e) { e.printStackTrace(); } }
上面的单元测试中,分别通过不同方式调用一亿次Date类型的getTime和setTime方法,输出如下:
time=1362806708572
time1=33333333
time2=33333333
直接调用耗时:18ms
Invokers调用耗时:120ms
JDK反射调用耗时:5352ms
FastMethod调用耗时:5057ms
可见Invokes的性能和直接调用已经接近了(实际上,如果接口处声明为准确参数类型而不是通用类型的话,会和直接调用性能一样),和传统反射相比相差两个数量级。
注:测试机器是Macbook Pro 374,虚拟机是JDK 6。
另一个例子,实现传统的通用反射接口(性能也是最好的)。测试代码如下:
@Test public void testInvoker() { try { Date date = new Date(); Method getMethod = Date.class.getMethod("getTime"); getMethod.setAccessible(true); Method setMethod = Date.class.getMethod("setTime", Long.TYPE); setMethod.setAccessible(true); Invoker get = Invokers.newInvoker(getMethod); Invoker set = Invokers.newInvoker(setMethod); FastClass fastClass = FastClass.create(Date.class); FastMethod fastGetMethod = fastClass.getMethod(getMethod); FastMethod fastSetMethod = fastClass.getMethod(setMethod); System.out.println(get.invoke(date, new Object[] {})); set.invoke(date, new Object[] { 333333L }); System.out.println(get.invoke(date, new Object[] {})); long t0 = System.currentTimeMillis(); for (int i = 0; i < 100000000; i++) { get.invoke(date, new Object[] {}); set.invoke(date, new Object[] { 333333L }); } long t1 = System.currentTimeMillis(); System.out.println("Invoker调用耗时:" + (t1 - t0) + "ms"); t1 = System.currentTimeMillis(); for (int i = 0; i < 100000000; i++) { getMethod.invoke(date, new Object[] {}); setMethod.invoke(date, new Object[] { 333333L }); } long t2 = System.currentTimeMillis(); System.out.println("JDK反射调用耗时:" + (t2 - t1) + "ms"); t2 = System.currentTimeMillis(); for (int i = 0; i < 100000000; i++) { fastGetMethod.invoke(date, new Object[] {}); fastSetMethod.invoke(date, new Object[] { 333333L }); } long t3 = System.currentTimeMillis(); System.out.println("CGLIB反射调用耗时:" + (t3 - t2) + "ms"); } catch (Exception e) { e.printStackTrace(); } }
输出结果如下(和上面的单元测试一样的环境):
1362857121037
333333
Invoker调用耗时:131ms
JDK反射调用耗时:5106ms
CGLIB反射调用耗时:4610ms
Invokers的代码如下(需javassist支持,asm生成字节码太麻烦 ):
import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.Map; import java.util.WeakHashMap; import javassist.ClassPool; import javassist.CtClass; import javassist.CtConstructor; import javassist.CtField; import javassist.CtMethod; import org.apache.commons.lang3.reflect.MethodUtils; /** * 快速动态方法调用器 * * @author * */ public class Invokers { /** * 调用器池 */ final private static Map<Method, Invoker> INVOKER_MAP = new WeakHashMap<Method, Invokers.Invoker>(); /** * 公共调用器池 */ final private static Map<Integer, Invoker> PUBLIC_INVOKER_MAP = new WeakHashMap<Integer, Invoker>(); /** * 调用器接口 */ public static interface Invoker { /** * 获取方法本身 * * @return */ Method method(); /** * 调用方法 * * @param host * 执行对象 * @param args * 执行参数 * @return */ Object invoke(Object host, Object[] args); } /** * 输出类型信息 * * @param argTypes * @return */ private static String argumentTypesToString(Class<?>[] argTypes) { StringBuilder buf = new StringBuilder(); buf.append("("); if (argTypes != null) { for (int i = 0; i < argTypes.length; i++) { if (i > 0) { buf.append(", "); } Class<?> c = argTypes[i]; buf.append((c == null) ? "null" : c.getName()); } } buf.append(")"); return buf.toString(); } /** * 快捷调用公共方法(性能较差) * * @param host * 宿主对象 * @param name * 方法名 * @param args * 方法参数 * @return 执行结果 * @throws NoSuchMethodException * 如果没有相应的方法 */ public static Object invokePublic(Object host, String name, Object... args) throws NoSuchMethodException { final Class<?> clazz = host instanceof Class ? (Class<?>) host : host .getClass(); args = args == null ? new Object[] { null } : args; Class<?>[] paramTypes = new Class[args.length]; for (int i = 0; i < paramTypes.length; i++) { paramTypes[i] = args[i] == null ? null : args[i].getClass(); } int[] keys = new int[3]; keys[0] = clazz.hashCode(); keys[1] = name.hashCode(); keys[2] = Arrays.hashCode(paramTypes); int key = Arrays.hashCode(keys); Invoker invoker = PUBLIC_INVOKER_MAP.get(key); if (invoker == null) { Method method = MethodUtils.getMatchingAccessibleMethod(clazz, name, paramTypes); if (method == null) { throw new NoSuchMethodException(clazz.getName() + "." + name + argumentTypesToString(paramTypes)); } invoker = newInvoker(method); PUBLIC_INVOKER_MAP.put(key, invoker); } return invoker.invoke(host, args); } /** * 根据传入的方法创建快速调用器。 比cglib的性能快4到40倍之间。 * * @param method * 方法对象 * @return 调用器 */ public static Invoker newInvoker(Method method) { Invoker invoker = INVOKER_MAP.get(method); if (invoker == null) { StringBuilder proxyClassNameBuilder = new StringBuilder(); proxyClassNameBuilder.append("proxy.invoker.method$"); proxyClassNameBuilder.append(method.hashCode()); String proxyClassName = proxyClassNameBuilder.toString(); try { Class<?> proxyClass; try { proxyClass = Class.forName(proxyClassName); } catch (Throwable e) { ClassPool cp = new ClassPool(true); CtClass cc = cp.makeClass(proxyClassName); cc.addField(CtField.make( "private java.lang.reflect.Method m;", cc)); CtConstructor ctConstructor = new CtConstructor( new CtClass[] { cp.get(Method.class.getName()) }, cc); ctConstructor .setBody("{this.m=(java.lang.reflect.Method)$1;}"); cc.addConstructor(ctConstructor); cc.addInterface(cp.get(Invoker.class.getName())); cc.addMethod(CtMethod .make("public java.lang.reflect.Method method(){return m;}", cc)); StringBuilder invokeCode = new StringBuilder(); invokeCode .append("public Object invoke(Object host, Object[] args){"); StringBuilder parameterCode = new StringBuilder(); for (int i = 0; i < method.getParameterTypes().length; i++) { if (i > 0) { parameterCode.append(","); } Class<?> parameterType = method.getParameterTypes()[i]; parameterCode.append(generateCast("args[" + i + "]", Object.class, parameterType)); } if (method.getParameterTypes().length > 0) { invokeCode.append("if(args==null||args.length!="); invokeCode.append(method.getParameterTypes().length); invokeCode .append(")throw new IllegalArgumentException(\"wrong number of arguments\");"); } StringBuilder executeCode = new StringBuilder(); executeCode.append("(("); executeCode.append(method.getDeclaringClass() .getCanonicalName()); executeCode.append(")"); String objCode = Modifier.isStatic(method.getModifiers()) ? "" : "host"; executeCode.append(objCode); executeCode.append(")."); executeCode.append(method.getName()); executeCode.append("("); executeCode.append(parameterCode); executeCode.append(")"); if (!method.getReturnType().equals(Void.TYPE)) { invokeCode.append("return "); invokeCode.append(generateCast(executeCode.toString(), method.getReturnType(), Object.class)); invokeCode.append(";"); } else { invokeCode.append(executeCode.toString()); invokeCode.append(";return null;"); } invokeCode.append("}"); cc.addMethod(CtMethod.make(invokeCode.toString(), cc)); proxyClass = cc.toClass(); } invoker = (Invoker) proxyClass.getConstructor(Method.class) .newInstance(method); INVOKER_MAP.put(method, invoker); } catch (Throwable e) { if (e instanceof RuntimeException) { throw (RuntimeException) e; } throw new RuntimeException(e); } } return invoker; } /** * 快速动态调用宿主方法。 如果指定了方法名,则执行方法时只会调用指定了的方法。 <br/> * 如果没有指定方法名,则调用宿主中对应接口类的同名方法。 * * @param superClass * 接口类 * @param hostClass * 宿主类 * @param methodName * 宿主方法名(可选) * @param hostMethodParameterTypes * 宿主方法参数(可选) * @param hostMethodReturnType * 宿主方法返回类型(可选) * @return 代理实例 */ @SuppressWarnings("unchecked") public static <T> T newInvoker(Class<T> superClass, Class<?> hostClass, String methodName, Class<?>[] hostMethodParameterTypes, Class<?> hostMethodReturnType) { try { methodName = methodName == null ? null : methodName.trim(); StringBuilder proxyClassNameBuilder = new StringBuilder(); proxyClassNameBuilder.append("proxy.invoker$"); proxyClassNameBuilder.append(superClass.hashCode() + 10000000000L); proxyClassNameBuilder.append("$"); proxyClassNameBuilder.append(hostClass.hashCode() + 10000000000L); proxyClassNameBuilder.append("$"); if (methodName != null && !methodName.equals("")) { proxyClassNameBuilder.append(methodName); } proxyClassNameBuilder.append("$"); if (hostMethodParameterTypes != null && hostMethodParameterTypes.length > 0) { proxyClassNameBuilder.append(10000000000L + Arrays .hashCode(hostMethodParameterTypes)); } proxyClassNameBuilder.append("$"); if (hostMethodReturnType != null) { proxyClassNameBuilder .append(10000000000L + hostMethodReturnType.hashCode()); } String proxyClassName = proxyClassNameBuilder.toString(); Class<?> proxyClass; try { proxyClass = Class.forName(proxyClassName); } catch (Exception ex) { ClassPool cp = new ClassPool(true); CtClass cc = cp.makeClass(proxyClassName); if (superClass.isInterface()) { cc.addInterface(cp.get(superClass.getName())); } else { cc.setSuperclass(cp.get(superClass.getName())); } Method[] methods = superClass.getMethods(); for (Method method : methods) { int mod = method.getModifiers(); if (Modifier.isFinal(mod) || Modifier.isStatic(mod)) { continue; } Class<?>[] parameterTypes = method.getParameterTypes(); if (parameterTypes.length < 1 || (!hostClass.isAssignableFrom(parameterTypes[0]) && !parameterTypes[0] .isAssignableFrom(hostClass))) { throw new IllegalArgumentException( "The first argument is not a host instance"); } if (hostMethodParameterTypes != null && hostMethodParameterTypes.length != parameterTypes.length - 1) { throw new IllegalArgumentException( String.format( "The host method parameter types'number should be %d", parameterTypes.length - 1)); } Class<?> returnType = method.getReturnType(); StringBuilder methodCode = new StringBuilder(); StringBuilder paramCode = new StringBuilder(); methodCode.append("public "); methodCode.append(returnType.getCanonicalName()); methodCode.append(" "); methodCode.append(method.getName()); methodCode.append("("); for (int i = 0; i < parameterTypes.length; i++) { String canonicalName = parameterTypes[i] .getCanonicalName(); if (i > 0) { methodCode.append(","); if (i > 1) { paramCode.append(","); } if (hostMethodParameterTypes != null) { String param = generateCast("p" + i, parameterTypes[i], hostMethodParameterTypes[i - 1]); paramCode.append(param); } else { String param = generateCast("p" + i, parameterTypes[i], parameterTypes[i - 1]); paramCode.append(param); } } methodCode.append(canonicalName); methodCode.append(" p"); methodCode.append(i); } methodCode.append("){"); StringBuilder executeCode = new StringBuilder(); executeCode.append("(("); executeCode.append(hostClass.getCanonicalName()); executeCode.append(")p0)."); if (methodName == null) { executeCode.append(method.getName()); } else { executeCode.append(methodName); } executeCode.append("("); executeCode.append(paramCode); executeCode.append(")"); if (!returnType.equals(Void.TYPE)) { methodCode.append("return "); hostMethodReturnType = hostMethodReturnType == null ? returnType : hostMethodReturnType; String returnCode = generateCast( executeCode.toString(), hostMethodReturnType, returnType); methodCode.append(returnCode); } else { methodCode.append(executeCode); } methodCode.append(";"); methodCode.append("}"); cc.addMethod(CtMethod.make(methodCode.toString(), cc)); } proxyClass = cc.toClass(); } return (T) proxyClass.newInstance(); } catch (Exception e) { if (e instanceof RuntimeException) { throw (RuntimeException) e; } throw new RuntimeException(e); } } private static String generateCast(String arg, Class<?> fromClass, Class<?> toClass) { StringBuilder cast = new StringBuilder(); if (fromClass.isPrimitive() && !toClass.isPrimitive()) { Class<?> wraperClass = toClass; if (!isWraper(toClass)) { wraperClass = getWraper(fromClass); } cast.append("("); cast.append(toClass.getCanonicalName()); cast.append(")"); cast.append(wraperClass.getCanonicalName()); cast.append(".valueOf(("); cast.append(getPrimitive(wraperClass).getCanonicalName()); cast.append(")"); cast.append(arg); cast.append(")"); } else if (!fromClass.isPrimitive() && toClass.isPrimitive()) { cast.append("("); cast.append(toClass.getCanonicalName()); cast.append(")"); Class<?> wraperClass = fromClass; if (!isWraper(fromClass)) { wraperClass = getWraper(toClass); cast.append("(("); if (Number.class.isAssignableFrom(wraperClass)) { cast.append(Number.class.getCanonicalName()); } else { cast.append(wraperClass.getCanonicalName()); } cast.append(")"); cast.append(arg); cast.append(")"); } else { cast.append(arg); } cast.append("."); cast.append(getPrimitive(wraperClass).getCanonicalName()); cast.append("Value()"); } else { cast.append("("); cast.append(toClass.getCanonicalName()); cast.append(")"); cast.append(arg); } return cast.toString(); } private static Class<?> getPrimitive(Class<?> wraperClass) { if (wraperClass.equals(Integer.class)) { return Integer.TYPE; } if (wraperClass.equals(Short.class)) { return Short.TYPE; } if (wraperClass.equals(Long.class)) { return Long.TYPE; } if (wraperClass.equals(Float.class)) { return Float.TYPE; } if (wraperClass.equals(Double.class)) { return Double.TYPE; } if (wraperClass.equals(Byte.class)) { return Byte.TYPE; } if (wraperClass.equals(Character.class)) { return Character.TYPE; } if (wraperClass.equals(Boolean.class)) { return Boolean.TYPE; } if (wraperClass.equals(Void.class)) { return Void.TYPE; } return wraperClass; } private static Class<?> getWraper(Class<?> toClass) { if (toClass.equals(Integer.TYPE)) { return Integer.class; } if (toClass.equals(Short.TYPE)) { return Short.class; } if (toClass.equals(Long.TYPE)) { return Long.class; } if (toClass.equals(Float.TYPE)) { return Float.class; } if (toClass.equals(Double.TYPE)) { return Double.class; } if (toClass.equals(Byte.TYPE)) { return Byte.class; } if (toClass.equals(Character.TYPE)) { return Character.class; } if (toClass.equals(Boolean.TYPE)) { return Boolean.class; } if (toClass.equals(Void.TYPE)) { return Void.class; } return toClass; } private static boolean isWraper(Class<?> toClass) { if (toClass.equals(Integer.class)) { return true; } if (toClass.equals(Short.class)) { return true; } if (toClass.equals(Long.class)) { return true; } if (toClass.equals(Float.class)) { return true; } if (toClass.equals(Double.class)) { return true; } if (toClass.equals(Byte.class)) { return true; } if (toClass.equals(Character.class)) { return true; } if (toClass.equals(Boolean.class)) { return true; } if (toClass.equals(Void.class)) { return true; } return false; } /** * 快速动态调用宿主方法。 如果指定了方法名,则执行方法时只会调用指定了的方法。 <br/> * 如果没有指定方法名,则调用宿主中对应接口类的同名方法。 * * @param superClass * 接口类 * @param hostClass * 宿主类 * @param methodName * 方法名(可选) * @return 代理实例 */ public static <T> T newInvoker(Class<T> superClass, Class<?> hostClass, String methodName) { return newInvoker(superClass, hostClass, methodName, null, null); } /** * 快速动态调用宿主方法。调用宿主中对应接口类的同名方法。 * * @param superClass * 接口类 * @param hostClass * 宿主类 * @return 代理实例 */ public static <T> T newInvoker(Class<T> superClass, Class<?> hostClass) { return newInvoker(superClass, hostClass, null); } }
以Invokers为基础,自己实现了一个BeanMap,代码如下:
package com.vssq.framework.lang.data; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.io.Serializable; import java.lang.reflect.Method; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.WeakHashMap; import com.vssq.framework.lang.util.Invokers; /** * 自己实现的一个BeanMap,使用Invokers调用,最大限度提高性能 * * */ public class BeanMap extends AbstractMap<String, Object> implements Serializable { public static interface Getter { Object get(Object obj); } public static interface Setter { void set(Object obj, Object value); } public class PropertyMeta { PropertyDescriptor propertyDescriptor; String name; Getter reader; Setter writer; Class<?> type; private boolean hasReader; private boolean hasWriter; PropertyMeta(PropertyDescriptor propertyDescriptor) { this.propertyDescriptor = propertyDescriptor; } public String getName() { if (name == null) { name = propertyDescriptor.getName(); } return name; } public Getter getReader() { if (reader == null && !hasReader) { Method method = propertyDescriptor.getReadMethod(); if (method != null) { reader = Invokers.newInvoker(Getter.class, method.getDeclaringClass(), method.getName(), method.getParameterTypes(), method.getReturnType()); } hasReader = true; } return reader; } public Setter getWriter() { if (writer == null && !hasWriter) { Method method = propertyDescriptor.getWriteMethod(); if (method != null) { writer = Invokers.newInvoker(Setter.class, method.getDeclaringClass(), method.getName(), method.getParameterTypes(), method.getReturnType()); } hasWriter = true; } return writer; } public Class<?> getPropertyType() { if (type == null) { type = propertyDescriptor.getPropertyType(); } return type; } } public interface PropertyEntry<K, V> extends Entry<K, V> { public PropertyMeta getProperty(); public Class<?> getType(); public boolean canRead(); public boolean canWrite(); } /** * 类字段映射 */ private static final Map<Class<?>, Map<String, PropertyMeta>> classBeanMap = new WeakHashMap<Class<?>, Map<String, PropertyMeta>>(); /** * */ private static final long serialVersionUID = -3627407279602086245L; final private Object source; final private Class<?> sourceClass; private Map<String, PropertyMeta> propertyMetaMap; public BeanMap(Object source) { if (source == null) { throw new NullPointerException("The source object should't be null"); } this.source = source; this.sourceClass = source.getClass(); generateBeanMap(); } public Set<java.util.Map.Entry<String, Object>> entrySet() { final Map<String, PropertyMeta> propertyMap = propertyMetaMap; Set<java.util.Map.Entry<String, Object>> entrySet = new AbstractSet<Map.Entry<String, Object>>() { public Iterator<java.util.Map.Entry<String, Object>> iterator() { final Iterator<PropertyMeta> propertyIterator = propertyMap .values().iterator(); return new Iterator<java.util.Map.Entry<String, Object>>() { public boolean hasNext() { return propertyIterator.hasNext(); } public java.util.Map.Entry<String, Object> next() { final PropertyMeta property = propertyIterator.next(); return new PropertyEntry<String, Object>() { public String getKey() { return property.getName(); } public Object getValue() { try { Getter read = property.getReader(); Object value = read == null ? null : read .get(source); return value; } catch (Exception e) { throw wrapCause(e); } } public Object setValue(Object value) { try { Setter write = property.getWriter(); Getter read = property.getReader(); Object old = read == null ? null : read .get(source); if (write != null) { write.set(source, value); } return old; } catch (Throwable e) { throw wrapCause(e); } } public Class<?> getType() { return property.getPropertyType(); } public boolean canWrite() { return property.getWriter() != null; } public PropertyMeta getProperty() { return property; } public boolean canRead() { return property.getReader() != null; } }; } public void remove() { throw new UnsupportedOperationException(); } }; } public int size() { return propertyMap.size(); } }; return entrySet; } public Map<String, java.util.Map.Entry<String, Object>> entryMap() { final Map<String, PropertyMeta> propertyMap = propertyMetaMap; return new AbstractMap<String, Map.Entry<String, Object>>() { public int size() { return propertyMap.size(); } public boolean containsKey(Object key) { return propertyMap.containsKey(key); } public Entry<String, Object> get(Object key) { final PropertyMeta property = propertyMap.get(key); return new PropertyEntry<String, Object>() { public String getKey() { return property.getName(); } public Object getValue() { try { Getter read = property.getReader(); Object value = read == null ? null : read .get(source); return value; } catch (Exception e) { throw wrapCause(e); } } public Object setValue(Object value) { try { Setter write = property.getWriter(); Getter read = property.getReader(); Object old = read == null ? null : read.get(source); if (write != null) { write.set(source, value); } return old; } catch (Throwable e) { throw wrapCause(e); } } public Class<?> getType() { return property.getPropertyType(); } public boolean canWrite() { return property.getWriter() != null; } public PropertyMeta getProperty() { return property; } public boolean canRead() { return property.getReader() != null; } }; } public Set<java.util.Map.Entry<String, java.util.Map.Entry<String, Object>>> entrySet() { Set<java.util.Map.Entry<String, java.util.Map.Entry<String, Object>>> entrySet = new AbstractSet<java.util.Map.Entry<String, java.util.Map.Entry<String, Object>>>() { public int size() { return propertyMap.size(); } public Iterator<java.util.Map.Entry<String, java.util.Map.Entry<String, Object>>> iterator() { final Iterator<PropertyMeta> propertyIterator = propertyMap .values().iterator(); return new Iterator<Map.Entry<String, Entry<String, Object>>>() { public boolean hasNext() { return propertyIterator.hasNext(); } public java.util.Map.Entry<String, java.util.Map.Entry<String, Object>> next() { return new java.util.Map.Entry<String, java.util.Map.Entry<String, Object>>() { PropertyMeta property = propertyIterator .next(); public String getKey() { return property.getName(); } public java.util.Map.Entry<String, Object> getValue() { return new PropertyEntry<String, Object>() { public String getKey() { return property.getName(); } public Object getValue() { try { Getter read = property .getReader(); Object value = read == null ? null : read.get(source); return value; } catch (Exception e) { throw wrapCause(e); } } public Object setValue(Object value) { try { Setter write = property .getWriter(); Getter read = property .getReader(); Object old = read == null ? null : read.get(source); if (write != null) { write.set(source, value); } return old; } catch (Throwable e) { throw wrapCause(e); } } public Class<?> getType() { return property .getPropertyType(); } public boolean canWrite() { return property.getWriter() != null; } public PropertyMeta getProperty() { return property; } public boolean canRead() { return property.getReader() != null; } }; } public java.util.Map.Entry<String, Object> setValue( java.util.Map.Entry<String, Object> value) { throw new UnsupportedOperationException(); } }; } public void remove() { throw new UnsupportedOperationException(); } }; } }; return entrySet; } }; } public Set<String> keySet() { return propertyMetaMap.keySet(); } private Map<String, PropertyMeta> generateBeanMap() { try { if (propertyMetaMap == null) { propertyMetaMap = classBeanMap.get(sourceClass); if (propertyMetaMap == null) { propertyMetaMap = new TreeMap<String, PropertyMeta>(); PropertyDescriptor[] propertys = Introspector.getBeanInfo( sourceClass).getPropertyDescriptors(); for (PropertyDescriptor property : propertys) { String name = property.getName(); if ("class".equals(name)) { continue; } PropertyMeta propertyMeta = new PropertyMeta(property); propertyMetaMap.put(name, propertyMeta); } classBeanMap.put(sourceClass, propertyMetaMap); } } return propertyMetaMap; } catch (Throwable e) { throw wrapCause(e); } } public int size() { return propertyMetaMap.size(); } public boolean isEmpty() { return propertyMetaMap.isEmpty(); } public boolean containsKey(Object key) { return propertyMetaMap.containsKey(key); } public Object get(Object key) { try { PropertyMeta property = propertyMetaMap.get(key); Getter read = property.getReader(); Object value = read == null ? null : read.get(source); return value; } catch (IllegalArgumentException e) { throw wrapCause(e); } } public Object put(String key, Object value) { try { PropertyMeta property = propertyMetaMap.get(key); Setter write = property.getWriter(); Getter read = property.getReader(); Object old = read == null ? null : read.get(source); if (write != null) { write.set(source, value); } return old; } catch (IllegalArgumentException e) { throw wrapCause(e); } } /** * 设置值(避免put中返回旧值的性能损失) * * @param key * 键 * @param value * 值 */ public void set(String key, Object value) { try { PropertyMeta property = propertyMetaMap.get(key); Setter write = property.getWriter(); if (write != null) { write.set(source, value); } } catch (IllegalArgumentException e) { throw wrapCause(e); } } /** * 包裹异常 * * @param cause * @return */ public static RuntimeException wrapCause(Throwable cause) { if (cause instanceof RuntimeException) { return (RuntimeException) cause; } return new RuntimeException(cause); } }
算上创建时间的话,比cglib的BeanMap快得多。但是如果仅仅是执行get或者put方法,则还是稍慢于cglib的BeanMap(大约是cglib的BeanMap所耗时间的1.5倍左右),因为cglib内部字节码生成的Map是使用switch定位key的,这比HashMap还要快,无能为力了 。但常规使用下,经常是对新对象创建Map并且只需要遍历执行一次get/put,所以创建时间慢的话还是严重影响性能的,使用此BeanMap在创建上速度是cglib的10倍以上。很多开源库都依赖于BeanMap,如JSON解析等等,如能使用此API,相信相关库的性能也会跟着大幅提升。
相关推荐
接下来,我们来看如何用CGLib和反射实现简单的AOP。以下是一个基于这两种技术的ProxyDemo: 1. **CGLib实现AOP** 首先,定义一个接口或抽象类(例如`MyService`),然后创建其实现类(例如`MyServiceImpl`)。接...
1. **性能优势**:相比于使用Java反射机制,CGLib生成的代理对象在性能上更优,因为它避免了反射带来的开销。 2. **无需接口**:CGLib可以对没有实现接口的类进行代理,这是Java动态代理(JDK Proxy)无法做到的。 3...
首先,Java的动态代理基于Java的反射API实现,主要用于接口代理。当目标对象实现了至少一个接口时,我们可以使用`java.lang.reflect.Proxy`类来创建代理对象。这个代理对象会拦截调用并执行自定义逻辑。例如,在调用...
Java反射和动态代理是Java编程中的重要特性,它们在实现高度灵活和动态的代码执行上发挥着关键作用。本文将深入探讨这两个概念,以及如何在实际开发中利用它们。 首先,我们来理解Java反射(Reflection)。Java反射...
5. **反射API的使用**:在Java中,`java.lang.reflect`包提供了Class、Constructor、Method和Field等类,用于反射操作。例如,`Class.forName()`用于加载类,`Constructor.newInstance()`用于创建对象,`Method....
它比使用java反射的JDK动态代理要快。 CGLIB底层:使用字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。 CGLIB缺点:对于...
这样做的好处是提高了性能,因为直接操作字节码通常比使用反射更快。 在Java中,有两种常见的动态代理方式:Java内置的Java.lang.reflect.Proxy类和第三方库如CGlib。Java内置的Proxy类需要目标类实现至少一个接口...
- Cglib代理相比于基于接口的JDK动态代理,其创建代理对象的速度更快,但运行时的性能略逊色,因为每次调用方法都需要通过子类调用父类方法,增加了额外开销。 总的来说,Cglib子类代理是一种强大的工具,它使得...
提供了更高级的反射工具,如FastClass和FastMethod,它们比Java自带的反射API性能更高,因为它们避免了多次JVM调用开销。 在实际应用中,CGLIB常被用于以下场景: 1. **动态代理**:通过创建目标对象的子类并重写...
对于那些不支持接口的目标对象,CGLIB提供了比Java动态代理更广泛的适用性。 3. **Enhancer**:CGLIB中的`Enhancer`类是其主要的使用入口,它允许开发者指定要增强的类、回调对象以及其他的定制选项。通过调用`...
Java的反射和代理机制是两种强大的工具,它们在实现控制反转(Inversion of Control,简称IOC)模式中扮演着重要角色。IOC模式是一种设计模式,它将对象的创建和依赖关系的管理从代码中分离出来,使系统更加灵活、可...
cglib 2.2.2 chm api 字节码生成
CGlib通过创建子类而非接口实现动态代理,是因为在Java中,方法的调用通常通过虚方法实现,而虚方法调用比接口方法的调用速度要快。同时,子类可以利用JVM的优化,如方法内联,进一步提升性能。 7. **应用示例** ...
这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。 #### 二、Java反射机制的核心类 Java反射机制主要依赖于以下几个核心类: 1. **`Class`**:代表一个类或接口。 2. **`Constructor`**:...
这篇博文“利用java反射、注解及泛型模拟ORM实现”旨在探讨如何结合这三种技术来实现对象关系映射(ORM),这是一种将数据库表与Java对象之间进行绑定的技术,简化了数据操作。 首先,我们来理解一下这三个概念: ...
标签:cglib、jar包、java、中英对照文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。 双语...
- CGLIB通过`FastClass`和`MethodProxy`提高调用性能,它们能快速地执行方法调用,避免了反射带来的开销。 对比分析: - **JDK动态代理**:适用于目标类已经实现接口的情况,使用简单,但只能针对接口进行代理。 -...
Java动态代理是Java编程中一个重要的特性,它允许我们在运行时创建代理类,这些代理类可以作为原有类的代理,实现在调用原有方法前后添加额外的功能,如日志记录、事务管理、性能监控等。Java提供了两种主要的动态...
CGlib是Java编程语言中的一个库,主要用于生成子类,以此实现对现有类的动态代理。它是基于ASM库,能够直接操作字节码,从而在运行时创建新类的实例。在Java中,CGlib是一个非常重要的工具,特别是在AOP(面向切面...