返回顶部

java反射性能研究

  目录
    1、反射的运行速度
      1.1测试赋值/取值基本的方法调用
      1.2分析慢的原因
      1.3反射调用的主要过程
        1.3.1加载类
        1.3.2创建实例
        1.3.3获取方法
        1.3.4调用方法
      1.4改进
        1.4.1缓存
        1.4.2还有哪里可以改进?
        1.4.3结论
    2、java反射的实现
      2.1使用javassist生成代理类
    3、解决方案
    4、遇到的问题

1.反射的运行速度
1.1测试赋值/取值基本的方法调用
  测试结果和JDK版本和以及测试用例的选取差别很大。测试用例可以说明的问题是相对而言的快慢, 即比较直接访问和反射访问的相对值。
在相同的逻辑下,调用100万次,结果如下
直接访问,测试代码如下
		
/**功能说明:性能研究,直接访问对象字段
 * 主要确认反射速度慢的原因
 * @author:linghushaoxia
 * @time:2017年4月29日下午3:19:11
 * @version:1.0
 * 为中国羸弱的技术撑起一片自立自强的天空
 */
public class ReflectionPerformance {
	public static void main(String[] args) {
		VisitDirect.visitDitectMain();
	}
}
/**
* 现实就是实现理想的过程
*/

/**
 * 
 * 功能说明:直接访问测试
 * @time:2017年4月29日下午3:40:54
 * @author:linghushaoxia
 * @exception:
 *
 */
public static void visitDitectMain(){
	/**
	 * 访问次数
	 * 100万次
	 */
	long count=1000000L;
	/**
	 * 开始测试
	 */
	long start = System.nanoTime();
	for(long i=0;i<count;i++){
		visitDitect();
	}
	long end = System.nanoTime();
	System.out.println("直接访问耗时:"+(end-start)/1000000+"ms");
}
/**
 * 
 * 功能说明:直接访问对象字段
 * @time:2017年4月29日下午3:29:39
 * @author:linghushaoxia
 * @exception:
 *
 */
public static void visitDitect(){
	Universe universe = new Universe();
	/**
	 * 赋值
	 */
	universe.setAge(1000000000000000000L);
	universe.setCoordinate("UN-1");
	universe.setExpand(true);
	universe.setRadius(10000000);
	/**
	 *取值
	 */
	universe.getAge();
	universe.getCoordinate();
	universe.getRadius();
}
		
		
反射访问,测试代码如下
			
/**功能说明:性能研究,反射访问字段
 * 主要确认反射速度慢的原因
 * @author:linghushaoxia
 * @time:2017年4月29日下午3:19:11
 * @version:1.0
 * 为中国羸弱的技术撑起一片自立自强的天空
 */
public class ReflectionPerformance {
	
	
	public static void main(String[] args) {
		VisitRefelct.visitReflectMain();			
	}
}

/**
* 现实就是实现理想的过程
*/
/**
 * 
 * 功能说明:反射访问测试
 * @time:2017年4月29日下午3:40:54
 * @author:linghushaoxia
 * @exception:
 *
 */
public static void visitReflectMain(){
	//访问次数,100万次
	long count=1000000L;
	/**
	 * 开始测试
	 */
	long start = System.nanoTime();
	//计时起始索引值
	int countStart=20;
	String className = "com.linghushaoxia.javabase.reflection.research.Universe";
	try {
		Class<?> universeClass =Class.forName(className);
		for(long i=0;i<count;i++){
			//为了测试缓存效果,从第二次开始计时
			if (countStart==i) {
				start = System.nanoTime();
			}
			visitRefelct(universeClass);
		}
	} catch (Exception e) {
		e.printStackTrace();
	}
	
	long end = System.nanoTime();
	System.out.println("反射访问耗时:"+(end-start)/1000000+"ms");
}
			
		
1.2分析慢的原因
  了解了反射的执行过程,才能知道它为什么慢。
1.3反射调用的主要过程
  加载类---->创建实例---->获取方法---->调用方法 接着细分每一个过程,并对可以提高性能的地方进行分析
1.3.1加载类
  Class.forName对class文件进行加载、校验会耗费时间 在java语言层面,最终会调用java.lang.Class.forName0,这是一个native方法, 在虚拟机层面,最终会调用jniHandles类的方法,JNIHandleBlock::allocate_handle(oop obj) 虽然,jvm会对加载的类进行缓存,但是仍无必要频繁调用。
这一步可以改进:
a)缓存
b)系统起始阶段预先加载(如何可以的话)
1.3.2创建实例
  正常业务,通常无法避免
1.3.3获取方法
  Class.getDeclaredMethod---->Class.checkMemberAccess---->Class.searchMethods----ReflectAccess.copyMethod 这一步涉及到校验、搜索方法,可以说是一个耗费时间的操作,而方法一旦搜索一次,就可以固定了,变动的是参数 可以改进
1.3.4调用方法
  Method.invoke,能否进行改进,还有疑问,先把可以改进的地方改进了。
1.4改进
  1.4.1缓存
  对Class对象和Method对象做缓存,优化结果
改进代码如下:
 			
/**功能说明:性能研究,缓存反射方法和class对象
 * 主要确认反射速度慢的原因
 * @author:linghushaoxia
 * @time:2017年4月29日下午3:19:11
 * @version:1.0
 * 为中国羸弱的技术撑起一片自立自强的天空
 */
public class ReflectionPerformance {
	
	
	public static void main(String[] args) {
		VisitRefelct.visitReflectMain();

	}
}
/**
* 现实就是实现理想的过程
*/

/**
 * 
 * 功能说明:反射访问测试
 * @time:2017年4月29日下午3:40:54
 * @author:linghushaoxia
 * @exception:
 *
 */
public static void visitReflectMain(){
	//访问次数,100万次
	long count=1000000L;
	/**
	 * 开始测试
	 */
	long start = System.nanoTime();
	//计时起始索引值
	int countStart=20;
	String className = "com.linghushaoxia.javabase.reflection.research.Universe";
	try {
		Class<?> universeClass =ReflectUtil.getClass(className);
		for(long i=0;i<count;i++){
			//为了测试缓存效果,从第二次开始计时
			if (countStart==i) {
				start = System.nanoTime();
			}
			visitRefelctCache(universeClass);
		}
	} catch (Exception e) {
		e.printStackTrace();
	}
	
	long end = System.nanoTime();
	System.out.println("反射访问耗时:"+(end-start)/1000000+"ms");
}
 			
 		
反射工具类,ReflectUtil
	
/**功能说明:反射工具类,缓存方法和class对象
* @author:linghushaoxia
* @time:2017年4月30日下午4:18:30
* @version:1.0
* 为中国羸弱的技术撑起一片自立自强的天空
*/
public class ReflectUtil {
	//类缓存
	private static Map<String, Class<?>> classCache = new ConcurrentHashMap<String, Class<?>>();
	//方法缓存
	private static Map<MethodProperty, Method> methodCache = new ConcurrentHashMap<MethodProperty, Method>();
	
	/**
	 * 
	 * 功能说明:获取class对象
	 * @param className
	 * 类名称
	 * @return Class<?>
	 * @time:2017年4月30日下午5:04:46
	 * @author:linghushaoxia
	 * @exception:
	 *
	 */
	public static Class<?> getClass(String className){
		//返回结果
		Class<?> classResult=null;
		//先从缓存获取
		if (classCache.containsKey(className)) {
			classResult= classCache.get(className);
		}else {
			//新加载
			try {
				classResult = Class.forName(className);
				classCache.put(className, classResult);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		return classResult;
	}
	/**
	 * 
	 * 功能说明:获取方法
	 * @param className
	 * 类名
	 * @param methodName
	 * 方法名
	 * @param params
	 * 参数类型列表
	 * @return Method
	 * @time:2017年4月30日下午5:06:30
	 * @author:linghushaoxia
	 * @exception:
	 *
	 */
	public static Method getMethod(String className,String methodName,Class<?>... params) throws SecurityException{
		//返回结果
		Method methodResult=null;
		MethodProperty methodProperty = new MethodProperty(className,methodName, params);
		if (methodCache.containsKey(methodProperty)) {
			methodResult = methodCache.get(methodProperty);
		}else {
			try {
				methodResult = getClass(className).getDeclaredMethod(methodName, params);
				methodResult.setAccessible(true);
				methodCache.put(methodProperty, methodResult);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return methodResult;
}
/**功能说明:方法属性描述
 * @author:linghushaoxia
 * @time:2017年4月30日下午4:27:39
 * @version:1.0
 * 为中国羸弱的技术撑起一片自立自强的天空
 */
public class MethodProperty {
	//类名
	private String className;
	//方法名
	private String methodName;
	//方法参数
	private Class<?>[] params;
	public MethodProperty(){
		
	}
	public MethodProperty(String className ,String methodName,Class<?> ... params){
		this.className=className;
		this.methodName=methodName;
		this.params = params;
	}
	@Override
	public boolean equals(Object object){
		if (object==null) {
			return false;
		}
		if (this==object) {
			return true;
		}else {
			if (object instanceof MethodProperty) {
				MethodProperty methodProperty = (MethodProperty)object;
				//方法名相同
				if (className!=null&&methodProperty.getClassName()!=null
						&&className.equals(methodProperty.getClassName())
						&&methodName!=null&&methodProperty.getMethodName()!=null
						&&methodName.equals(methodProperty.getMethodName())) {
					if (params==null&&methodProperty.getParams()==null) {
						return true;
					}else {
						if (params!=null&&methodProperty.getParams()!=null&¶ms.length==methodProperty.getParams().length) {
							for(int i=0;i<params.length;i++){
								if (params[i]!=methodProperty.getParams()[i]) {
									return false;
								}
							}
							return true;
						}
					}
					
				}
			}
		}
		return false;
		
	}
	//hash值的求解方法可以改善
	@Override
	public int hashCode(){
		int result=19;
		//类名
		result=className.hashCode()*result+methodName.hashCode();
		//参数的hash值
		if (params!=null) {
			for (Class<?> class1 : params) {
				if (class1.getName()!=null) {
					result = result*class1.getName().hashCode();
				}
			}
		}
		
		return result;
		
	}
	public String getMethodName() {
		return methodName;
	}
	public void setMethodName(String methodName) {
		this.methodName = methodName;
	}
	public Class<?>[] getParams() {
		return params;
	}
	public void setParams(Class<?>[] params) {
		this.params = params;
	}
	public String getClassName() {
		return className;
	}
	public void setClassName(String className) {
		this.className = className;
	}
	@Override
	public String toString() {
		return "{\""
				+ (className != null ? "className\":\"" + className + "\",\""
						: "")
				+ (methodName != null ? "methodName\":\"" + methodName
						+ "\",\"" : "")
				+ (params != null ? "params\":\"" + Arrays.toString(params)
						: "") + "\"}";
	}
	
}

/**
* 现实就是实现理想的过程
*/
 	
 		
加上缓存后,性能有5-10倍的改善。 因为使用到HashMap,对key求hash值还存在改善的空间,然而改善的空间不大。

1.4.2还有哪里可以改进?
  目前调用过程invoke,还没没有研究。看一下java的invoke执行过程
		
		public Object invoke(Object obj, Object... args)
        throws IllegalAccessException, IllegalArgumentException,
           InvocationTargetException
		    {
		        if (!override) {
		            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
		                Class<?> caller = Reflection.getCallerClass();
		                checkAccess(caller, clazz, obj, modifiers);
		            }
		        }
		        MethodAccessor ma = methodAccessor;             // read volatile
		        if (ma == null) {
		            ma = acquireMethodAccessor();
		        }
		        return ma.invoke(obj, args);
		    }
		
	
  从代码中看,主要涉及到如下过程 Method.invoke--->check(Reflection.quickCheckMemberAccess,AccessibleObject.checkAccess)---->获取MethodAccessor ---->执行调用invoke

1)校验
  override为true,可以跳过校验,这用来校验方法或者字段的方法属性, 实际业务中,在了解要访问方法的情况下,可以不进行校验,设置方法的访问属性为true,Mehthod.setAccessible(true);
	
	if (!override) {
            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
                Class<?> caller = Reflection.getCallerClass();
                checkAccess(caller, clazz, obj, modifiers);
            }
        }
	

优化结果   这一步优化,除了JDK7之前,没有明显的效果;当然JDK7效果也不好。 2)获取MethodAccessor
	
	// NOTE that there is no synchronization used here. It is correct
    // (though not efficient) to generate more than one MethodAccessor
    // for a given Method. However, avoiding synchronization will
    // probably make the implementation more scalable.
    private MethodAccessor acquireMethodAccessor() {
        // First check to see if one has been created yet, and take it
        // if so
        MethodAccessor tmp = null;
        if (root != null) tmp = root.getMethodAccessor();
        if (tmp != null) {
            methodAccessor = tmp;
        } else {
            // Otherwise fabricate one and propagate it up to the root
            tmp = reflectionFactory.newMethodAccessor(this);
            setMethodAccessor(tmp);
        }

        return tmp;
    }
	

  首次调用时,会执行reflectionFactory.newMethodAccessor(this) 源码如下
	
  public MethodAccessor newMethodAccessor(Method method) {
        checkInitted();

        if (noInflation) {
            return new MethodAccessorGenerator().
                generateMethod(method.getDeclaringClass(),
                               method.getName(),
                               method.getParameterTypes(),
                               method.getReturnType(),
                               method.getExceptionTypes(),
                               method.getModifiers());
        } else {
            NativeMethodAccessorImpl acc =
                new NativeMethodAccessorImpl(method);
            DelegatingMethodAccessorImpl res =
                new DelegatingMethodAccessorImpl(acc);
            acc.setParent(res);
            return res;
        }
    }
	
  获取MethodAccessor的实例逻辑主要分为两种,通过标志noInflation,来判断是否增大到一定值,来选择逻辑分支. 查看noInflation的注释
//
// "Inflation" mechanism. Loading bytecodes to implement
// Method.invoke() and Constructor.newInstance() currently costs
// 3-4x more than an invocation via native code for the first
// invocation (though subsequent invocations have been benchmarked
// to be over 20x faster). Unfortunately this cost increases
// startup time for certain applications that use reflection
// intensively (but only once per class) to bootstrap themselves.
// To avoid this penalty we reuse the existing JVM entry points
// for the first few invocations of Methods and Constructors and
// then switch to the bytecode-based implementations.
  "通胀"机制。在前几次调用中,加载字节码实现方法调用和生成实例,通常比本地代码花费3-4倍的时间(虽然后续的调用经过检测速度快乐20倍以上)。 不幸的是,这个花费增加了某些使用反射引导自己的应用的启动时间,为了避免这个缺点,在前几次的方法和构造器调用中,我们重用了已经存在的jvm的进入点 然后切换到基于字节码的实现中。 MethodAccessorGenerator是使用字节码生成技术,生成java代码版本的MethodAccessor,而NativeMethodAccessorImpl是native版本的MethodAccessor 查看NativeConstructorAccessorImpl,生成实例和方法调用的逻辑都会对,调用次数自增,并对临界值进行校验 可以看到调用NativeConstructorAccessorImpl.newInstance NativeMethodAccessorImpl.invoke源码如下
    	
public Object invoke(Object obj, Object[] args)
   throws IllegalArgumentException, InvocationTargetException{	
   //次数达到一定程度,使用字节码生成代理
     if (++numInvocations > ReflectionFactory.inflationThreshold()) {
         MethodAccessorImpl acc = (MethodAccessorImpl)
             new MethodAccessorGenerator().
                 generateMethod(method.getDeclaringClass(),
                                method.getName(),
                                method.getParameterTypes(),
                                method.getReturnType(),
                                method.getExceptionTypes(),
                                method.getModifiers());
         parent.setDelegate(acc);
     }
	//调用native方法
     return invoke0(method, obj, args);
 }
    	
    
  现在清楚了,获取到的MethodAccessor的实现,分为两套一个是native版本的,一套是java版本的,第16次开始调用java版本的,而且java版本的性能会随着调用越来越高, 最终会快于native版本的20倍以上。
3)MethodAccessor.invoke
  方法的正常调用,是调用方法DelegatingMethodAccessorImpl.invoke,调用他内部的delegate.invoke 在NativeMethodAccessorImpl的版本中,达到阈值调用MethodAccessorGenerator.generateMethod会生成java版本的代理方法 到这里,是不是可以测试下效率低是不是native版本的问题?可以把计时起始次数调整到16跳过native版本的逻辑 经过测试,无明显改善。
1.4.3结论
  经过以上的测试,得出以下结论
1)java的反射实现,性能低于直接调用,反射调用的时间成本是直接调用的10倍以上;
2)对造成性能低的原因,进行了推测和验证,结论是基于做出的改进,对性能几乎没有提升。缓存是有明显的提升的,提升约10倍. 那么,就只说明java版本的反射实现,效率也低。
按照道理讲,java语言本身调用方法,应该很快,应该和直接调用相当。为什么这么低?
2、java反射的实现
  反射调用方法时Method.invoke调用的是MethodAccessor.invoke,MethodAccessor是一个接口 具体实现是动态生成的,开始由ReflectionFactory.newMethodAccessor来生成,
	
public MethodAccessor newMethodAccessor(Method method) {
       checkInitted();

       if (noInflation) {
           return new MethodAccessorGenerator().
               generateMethod(method.getDeclaringClass(),
                              method.getName(),
                              method.getParameterTypes(),
                              method.getReturnType(),
                              method.getExceptionTypes(),
                              method.getModifiers());
       } else {
           NativeMethodAccessorImpl acc =
               new NativeMethodAccessorImpl(method);
           DelegatingMethodAccessorImpl res =
               new DelegatingMethodAccessorImpl(acc);
           acc.setParent(res);
           return res;
       }
   }
	
  DelegatingMethodAccessorImpl在运行时,会将反射的实现由native版本切换至字节码版本, 字节码版本的是什么样子的呢?这里给出一个字节码生成的实例
测试类,一个普通java类

public class Business {
	public void invoke(java.lang.String p1,int p2,Long p3){
		System.out.println("p1="+p1);
		System.out.println("p2="+p2);
		System.out.println("p3="+p3);

	}
}

java生成的字节码如下
	
import com.linghushaoxia.javabase.reflection.research.Business;
import java.lang.reflect.InvocationTargetException;
import sun.reflect.MethodAccessorImpl;

public class GeneratedMethodAccessor1 extends MethodAccessorImpl {
	public Object invoke(Object arg0, Object[] arg1)
			throws InvocationTargetException {
		if (arg0 == null) {
			throw new NullPointerException();
		} else {
			String arg10000;
			Business arg9999;
			Long arg10002;
			int arg10001;
			try {
				arg9999 = (Business) arg0;
				if (arg1.length != 3) {
					throw new IllegalArgumentException();
				}

				arg10000 = (String) arg1[0];
				Object arg2 = arg1[1];
				if (arg2 instanceof Byte) {
					arg10001 = ((Byte) arg2).byteValue();
				} else if (arg2 instanceof Character) {
					arg10001 = ((Character) arg2).charValue();
				} else if (arg2 instanceof Short) {
					arg10001 = ((Short) arg2).shortValue();
				} else {
					if (!(arg2 instanceof Integer)) {
						throw new IllegalArgumentException();
					}

					arg10001 = ((Integer) arg2).intValue();
				}

				arg10002 = (Long) arg1[2];
			} catch (NullPointerException | ClassCastException arg4) {
				throw new IllegalArgumentException(arg4.toString());
			}

			try {
				arg9999.invoke(arg10000, arg10001, arg10002);
				return null;
			} catch (Throwable arg3) {
				throw new InvocationTargetException(arg3);
			}
		}
	}
}
  可以看到,java为目标方法生成了一个类,该类持有目标对象的实例,对参数经过校验,转换直接调用目标对象的方法 使用代理的方式进行访问,这段代码和直接访问的区别在哪里?
前期需要生成代理类,耗费些时间,可以加入缓存
缓存加入后,有提升,可是还是差不少。
  问题最终只能定位到类型的转换。Object arg0, Object[] arg1,目标对象和参数涉及到多次类型转换
在实现中,和直接调用相比,除了这一行调用其余逻辑都是额外加入的,额外的这一些逻辑就是反射的开销。
arg9999.invoke(arg10000, arg10001, arg10002);
实际使用中,为了更好的控制代理生成,可以使用javassist来生成字节码
2.1使用javassist生成代理类
  生成的代理类GeneratedMethodAccessor$0.class
	
package sun.reflect;
import com.linghushaoxia.javabase.reflection.research.Business;
import java.lang.reflect.InvocationTargetException;
import sun.reflect.MethodAccessor;

public class GeneratedMethodAccessor$0 implements MethodAccessor {
	public Object invoke(Object arg0, Object[] arg1)
			throws IllegalArgumentException, InvocationTargetException {
		Business arg2 = (Business) arg0;
		arg2.invokePrint((String) arg1[0],
				Integer.valueOf(String.valueOf(arg1[1])).intValue(),
				(Long) arg1[2]);
		return null;
	}
}
	

生成方法如下
	
/**
 * 
 * 功能说明:根据传入参数生成目标方法的代理对象
 * @param className
 * 类名
 * @param methodName
 * 方法名
 * @param returnType
 * 返回类型
 * @param modifier
 * 访问权限修饰符
 * @param params
 * 参数类型列表
 * @return MethodAccessor
 * @time:2017年5月1日下午11:56:57
 * @author:linghushaoxia
 * @exception:
 *
 */
public static MethodAccessor generateMethod(String className,String methodName,Class returnType,int modifier,Class...params){
	MethodAccessor methodResult=null;
	try {
		ClassPool classPool = ClassPool.getDefault();
		/**
		 * 以下手工方式写出代理方法
		 * 作为示例,略去了异常处理和校验
		 */
		//生成的类名
		String classname="sun.reflect.GeneratedMethodAccessor$"+count++;
		CtClass ctClass= classPool.makeClass(classname);
		classPool.importPackage("java.lang");
		classPool.importPackage("java.lang.reflect");
		ctClass.setModifiers(Modifier.PUBLIC);
		//实现MethodAccessor,和反射api无缝结合
		CtClass[] interfaces={classPool.get("sun.reflect.MethodAccessor")};
		ctClass.setInterfaces(interfaces);
		//方法体
		StringBuilder proxyInvokeBody = new StringBuilder();
		//代理方法参数的声明
		StringBuilder proxyParamsDeclare = new StringBuilder();
		//调用目标类的参数传值
		StringBuilder targetParamValues = new StringBuilder();
		for(int  i=0;i<params.length;i++){
			if (params[i].getName().equals("int")) {
				targetParamValues.append("Integer.valueOf((String.valueOf(").append(" params[").append(i).append("]").append("))).intValue()");	
			}else {
				targetParamValues.append("(").append(params[i].getName()).append(")").append(" params[").append(i).append("]");
			}
			proxyParamsDeclare.append(params[i].getName()).append(" param").append(i);
		    if (i<params.length-1) {
		    	proxyParamsDeclare.append(",");
		    	targetParamValues.append(",");
		    }
		}
		
		/**
		 * 以实现sun.reflect.MethodAccessor方式生成代理时,返回值是Object类型
		 * 此处返回null
		 */
		if (returnType==null) {
		    proxyInvokeBody.append("public Object invoke(Object obj,").append("Object[] params").append(")").append(" throws IllegalArgumentException, InvocationTargetException ").append("{");
		    proxyInvokeBody.append("\n	");
		    proxyInvokeBody.append(className).append(" target").append("=").append("(").append(className).append(")").append("obj").append(";");
		    proxyInvokeBody.append("\n	");
		    proxyInvokeBody.append(" 	target.").append(methodName).append("(").append(targetParamValues.toString()).append(")").append(";");
		    proxyInvokeBody.append("\n return null;");
		    proxyInvokeBody.append("\n	}");
		}else if (returnType==Void.class) {
		    proxyInvokeBody.append("public void invoke(Object obj,").append("Object[] params").append(")").append(" throws IllegalArgumentException, InvocationTargetException ").append("{");
		    proxyInvokeBody.append("\n	");
		    proxyInvokeBody.append(className).append(" target").append("=").append("(").append(className).append(")").append("obj").append(";");
		    proxyInvokeBody.append("\n	");
		    proxyInvokeBody.append(" 	target.").append(methodName).append("(").append(targetParamValues.toString()).append(")").append(";");
		    proxyInvokeBody.append("\n	}");
		}
		CtMethod invokePrint =CtMethod.make(proxyInvokeBody.toString(), ctClass);
		
		ctClass.addMethod(invokePrint);
		//自定义的classloader,生成class
		ReflectClassLoader classLoader = ReflectClassLoader.getClassLoader();
		Class<?> generateClass= classLoader.defineClass(classname, ctClass.toBytecode());
		//保存到磁盘,查看具体代码
		ctClass.writeFile(classname);
		methodResult= (MethodAccessor) generateClass.newInstance();
		
	} catch (Exception e) {
		e.printStackTrace();
	}
	
	return methodResult;
} 
	
3、解决方案
1)缓存
缓存,是一个行之有效的方法
2)字节码优化
  java本身实现的反射,效率低的原因在于类型转换,如果可以避免大量的类型转换,效率就上去了。 类型转换的目的是为了保证接口的通用性,性能和通用性的矛盾,在此体现的淋漓尽致。 javassist和java本身生成的代理,效率一样的低。 那么,在保证通用性的前提下,只有通过对字节码进行优化,来减少类型转换造成的消耗。
4、遇到的问题
1)Exception in thread "main" java.lang.AbstractMethodError
  接口和实现类的声明不一致
2)java.lang.IllegalAccessException: Class XXX can not access a member of class with modifiers ""
  当前类继承了非public类或者当前类的访问权限,非public