java反射性能测试分析
java有别于其他编程语言而让我着迷的特性有很多,其中最喜欢的是接口设计,他让我们设计的东西具有美感。同样反射也是我比较喜欢的一个特性,他让程序自动运行,动态加载成为了可能,同时也是现在很多流行框架所必不可少的特性,struts,hibernate等都是,spring本身就是基于反射的就更不用说了。细细想来,似乎很少有不涉及到反射的框架。我自己设计框架的时候,开始也都是运用反射,但是越深入却让我越疑惑,反射的效率一直是我设计框架的心病。今天在优化 InstantMVC的时候就考虑怎么提高自动封装form的效率,struts是用的commons-beantuils,好像也没人说struts的效率不高,诚然,beanUtils中很多有用方便的特性让反射开发者着迷,但是通过我今天的测试,却发现beanUtils的易用性要付出巨大的性能代价,虽然在现在这个年代,这么点性能不算什么,但是对于我这种执着的人开发执着的框架,还是对性能有种独特的偏好,目前来说InstantMVC中用的是直接的反射简单封装,而InstantORM(我的持久层框架)中用到是自动生成pojo和相应的pojo辅助类来实现动态高效(比直接的反射高效10-20倍)执行Object的方法(一般是get和set),对于InstantMVC的form利用动态生成辅助类有一定的难度,不是说实现难度,而是对于运用该框架的web开发者来说,不够直接。所以还是主要考虑用反射的,废话不说,下面开始今天的测试。
首先,测试主要有三部分组成,测试创建对象的性能,测试set方法的性能,测试get方法的性能。我没有看过beanUtils的源代码,不过评我的经验想想BeanUtils应该是做了一些性能的优化的,初步猜测是第一次运行缓存Object的相应东东(具体是什么也不知道),所以测试的时候都是从第二次开始,忽略第一次。下面是测试代码(省略了异常抛出。)
public
class
MyBean {
String name;
int age;
String[] firends;
public static void main(String args[]) {
Object o1 = beanUtilsCreate();
Object o2 = javaCreate();
MyBean my = new MyBean();
long a = System.currentTimeMillis();
for ( int i = 0 ;i < 5000 ;i ++ ){
// 47
// beanUtilsCreate();
// 15
// javaCreate();
// 0
// manualCreate();
// 235
// beanUtilsSet(o1);
// 40
// javaSet(o2);
// 0
// manualSet(my);
// 203
// beanUtilsGet(o1);
// 47
// javaGet(o2);
// 0
// manualGet(my);
}
long b = System.currentTimeMillis();
System.out.println(b - a);
}
// ===============下面是 beanUtils的方法
public static Object beanUtilsCreate() {
Object ob = ConstructorUtils.invokeConstructor(MyBean. class , null );
return ob;
}
public static void beanUtilsSet(Object ob) {
BeanUtils.setProperty(ob, " name " , " 旺旺旺 " );
}
public static void beanUtilsGet(Object ob) {
BeanUtils.getProperty(ob, " name " );
}
// ===============下面是 java自身的直接反射的方法
public static Object javaCreate() {
Object ob = MyBean. class .newInstance();
return ob;
}
public static void javaSet(Object ob) {
Method m = MyBean. class .getDeclaredMethod( " setName " , new Class[]{String. class });
m.invoke(ob, new Object[]{ " 旺旺旺 " });
}
public static void javaGet(Object ob) {
Method m = MyBean. class .getDeclaredMethod( " getName " , new Class[ 0 ]);
m.invoke(ob, new Object[ 0 ]);
}
// ===============下面是 手动的创建对象
public static MyBean manualCreate(){
MyBean my = new MyBean();
return my;
}
public static void manualSet(MyBean my){
my.setName( " 旺旺旺 " );
}
public static void manualGet(MyBean my){
my.getName();
}
public int getAge() {
return age;
}
public void setAge( int age) {
this .age = age;
}
public String[] getFirends() {
return firends;
}
public void setFirends(String[] firends) {
this .firends = firends;
}
public String getName() {
return name;
}
public void setName(String name) {
this .name = name;
}
}
String name;
int age;
String[] firends;
public static void main(String args[]) {
Object o1 = beanUtilsCreate();
Object o2 = javaCreate();
MyBean my = new MyBean();
long a = System.currentTimeMillis();
for ( int i = 0 ;i < 5000 ;i ++ ){
// 47
// beanUtilsCreate();
// 15
// javaCreate();
// 0
// manualCreate();
// 235
// beanUtilsSet(o1);
// 40
// javaSet(o2);
// 0
// manualSet(my);
// 203
// beanUtilsGet(o1);
// 47
// javaGet(o2);
// 0
// manualGet(my);
}
long b = System.currentTimeMillis();
System.out.println(b - a);
}
// ===============下面是 beanUtils的方法
public static Object beanUtilsCreate() {
Object ob = ConstructorUtils.invokeConstructor(MyBean. class , null );
return ob;
}
public static void beanUtilsSet(Object ob) {
BeanUtils.setProperty(ob, " name " , " 旺旺旺 " );
}
public static void beanUtilsGet(Object ob) {
BeanUtils.getProperty(ob, " name " );
}
// ===============下面是 java自身的直接反射的方法
public static Object javaCreate() {
Object ob = MyBean. class .newInstance();
return ob;
}
public static void javaSet(Object ob) {
Method m = MyBean. class .getDeclaredMethod( " setName " , new Class[]{String. class });
m.invoke(ob, new Object[]{ " 旺旺旺 " });
}
public static void javaGet(Object ob) {
Method m = MyBean. class .getDeclaredMethod( " getName " , new Class[ 0 ]);
m.invoke(ob, new Object[ 0 ]);
}
// ===============下面是 手动的创建对象
public static MyBean manualCreate(){
MyBean my = new MyBean();
return my;
}
public static void manualSet(MyBean my){
my.setName( " 旺旺旺 " );
}
public static void manualGet(MyBean my){
my.getName();
}
public int getAge() {
return age;
}
public void setAge( int age) {
this .age = age;
}
public String[] getFirends() {
return firends;
}
public void setFirends(String[] firends) {
this .firends = firends;
}
public String getName() {
return name;
}
public void setName(String name) {
this .name = name;
}
}
上面代码首先创建一个MyBean,简单的name和age属性,然后get和set方法,在main方法中首先构建三个类:
Object o1
=
beanUtilsCreate();
Object o2 = javaCreate();
MyBean my = new MyBean();
为了防止beanUtils内部对第一次做了缓存操作而使测试不准确。
Object o2 = javaCreate();
MyBean my = new MyBean();
第二次开始连续循环5000次分别测试 Create,set,和get的性能。
结果显示如下:
===================================================
BeanUtils java自己反射 手动
创建: 47 15 0
set方法 235 40 0
get方法 203 47 0
===================================================
jdk 1.6,1G内存,AMD 2600+
从上面的结果可以看出,BeanUtils的性能确实不怎么样,这样的结果虽然在现代服务器都菜价了的年代,我还是要为struts和spring等基于反射的框架捏一把汗。不知道spring有没有对反射做过优化,不过上次看Ibatis的时候好像他提供了一个配置选项来增强字节码的反射效率,大概就是那种动态创建字节码的技术吧。
转自: http://www.blogjava.net/kingyaoo/archive/2008/06/07/206533.html