java有別于其他編程語(yǔ)言而讓我著迷的特性有很多,其中最喜歡的是接口設(shè)計(jì),他讓我們?cè)O(shè)計(jì)的東西具有美感。同樣反射也是我比較喜歡的一個(gè)特性,他讓程序自動(dòng)運(yùn)行,動(dòng)態(tài)加載成為了可能,同時(shí)也是現(xiàn)在很多流行框架所必不可少的特性,struts,hibernate等都是,spring本身就是基于反射的就更不用說(shuō)了。細(xì)細(xì)想來(lái),似乎很少有不涉及到反射的框架。我自己設(shè)計(jì)框架的時(shí)候,開(kāi)始也都是運(yùn)用反射,但是越深入?yún)s讓我越疑惑,反射的效率一直是我設(shè)計(jì)框架的心病。
今天在優(yōu)化
InstantMVC的時(shí)候就考慮怎么提高自動(dòng)封裝form的效率,struts是用的commons-beantuils,好像也沒(méi)人說(shuō)struts的效率不高,誠(chéng)然,beanUtils中很多有用方便的特性讓反射開(kāi)發(fā)者著迷,但是通過(guò)我今天的測(cè)試,卻發(fā)現(xiàn)beanUtils的易用性要付出巨大的性能代價(jià),雖然在現(xiàn)在這個(gè)年代,這么點(diǎn)性能不算什么,但是對(duì)于我這種執(zhí)著的人開(kāi)發(fā)執(zhí)著的框架,還是對(duì)性能有種獨(dú)特的偏好,目前來(lái)說(shuō)InstantMVC中用的是直接的反射簡(jiǎn)單封裝,而InstantORM(我的持久層框架)中用到是自動(dòng)生成pojo和相應(yīng)的pojo輔助類(lèi)來(lái)實(shí)現(xiàn)動(dòng)態(tài)高效(比直接的反射高效10-20倍)執(zhí)行Object的方法(一般是get和set),對(duì)于InstantMVC的form利用動(dòng)態(tài)生成輔助類(lèi)有一定的難度,不是說(shuō)實(shí)現(xiàn)難度,而是對(duì)于運(yùn)用該框架的web開(kāi)發(fā)者來(lái)說(shuō),不夠直接。所以還是主要考慮用反射的,廢話不說(shuō),下面開(kāi)始今天的測(cè)試。
首先,測(cè)試主要有三部分組成,測(cè)試創(chuàng)建對(duì)象的性能,測(cè)試set方法的性能,測(cè)試get方法的性能。我沒(méi)有看過(guò)beanUtils的源代碼,不過(guò)評(píng)我的經(jīng)驗(yàn)想想BeanUtils應(yīng)該是做了一些性能的優(yōu)化的,初步猜測(cè)是第一次運(yùn)行緩存Object的相應(yīng)東東(具體是什么也不知道),所以測(cè)試的時(shí)候都是從第二次開(kāi)始,忽略第一次。下面是測(cè)試代碼(省略了異常拋出。)
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]);
}
// ===============下面是 手動(dòng)的創(chuàng)建對(duì)象
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;
}
}
上面代碼首先創(chuàng)建一個(gè)MyBean,簡(jiǎn)單的name和age屬性,然后get和set方法,在main方法中首先構(gòu)建三個(gè)類(lèi):
Object o1=beanUtilsCreate();
Object o2=javaCreate();
MyBean my=new MyBean();
為了防止beanUtils內(nèi)部對(duì)第一次做了緩存操作而使測(cè)試不準(zhǔn)確。
第二次開(kāi)始連續(xù)循環(huán)5000次分別測(cè)試 Create,set,和get的性能。
結(jié)果顯示如下:
===================================================
BeanUtils java自己反射 手動(dòng)
創(chuàng)建: 47 15 0
set方法 235 40 0
get方法 203 47 0
===================================================
jdk 1.6,1G內(nèi)存,AMD 2600+
從上面的結(jié)果可以看出,BeanUtils的性能確實(shí)不怎么樣,這樣的結(jié)果雖然在現(xiàn)代服務(wù)器都菜價(jià)了的年代,我還是要為struts和spring等基于反射的框架捏一把汗。不知道spring有沒(méi)有對(duì)反射做過(guò)優(yōu)化,不過(guò)上次看Ibatis的時(shí)候好像他提供了一個(gè)配置選項(xiàng)來(lái)增強(qiáng)字節(jié)碼的反射效率,大概就是那種動(dòng)態(tài)創(chuàng)建字節(jié)碼的技術(shù)吧。
--InstantMVC:j2ee輕量級(jí)mvc框架