配色: 字号:
java反射机制性能优化
2016-12-02 | 阅:  转:  |  分享 
  
java反射机制性能优化

复制代码

importjava.lang.reflect.InvocationTargetException;

importjava.lang.reflect.Method;

importjava.util.HashMap;

importjava.util.Map;

importorg.apache.log4j.Logger;



publicclassDynamicServer{

privatestaticLoggerlog=Logger.getLogger(DynamicServer.class);

publicstaticMapclazzMap=newHashMap();

publicstaticMapobjMap=newHashMap();

publicstaticMapmetMap=newHashMap();

publicstaticMap>typeMap=newHashMap>();







/

通过反射+缓存高效的调用某个类里面的某个方法

/

publicstaticObjectcacheExce(Stringclazz,Stringmethod,Object[]os,Class[]cs)throwsNoSuchMethodException{

try{

intsize=0;

if(cs!=null){

size=cs.length;

}



Methodm=metMap.get(clazz+"_"+method+"_"+size);//用于区分重载的方法

Objectobj=objMap.get(clazz);



if(m==null||obj==null){

Classcl=clazzMap.get(clazz);

if(cl==null){

cl=Class.forName(clazz);

clazzMap.put(clazz,cl);//缓存class对象

}



if(obj==null){

obj=cl.newInstance();

objMap.put(clazz,obj);//缓存对象的实例

}



if(m==null){

m=cl.getMethod(method,cs);

metMap.put(clazz+"_"+method+"_"+size,m);//缓存Method对象

}

}

returnm.invoke(obj,os);//动态调用某个对象中的public声明的方法

}catch(Exceptione){

e.printStackTrace();

thrownewNoSuchMethodException();

}

}





/

通过反射+缓存获取指定类里面的指定方法的返回类型

/

publicstaticStringcacheType(Stringclazz,Stringmethod)throwsClassNotFoundException{

Mapclazzs=typeMap.get(clazz);

if(clazzs==null){

Mapmmap=newHashMap();

Classcl=Class.forName(clazz);

Method[]ms=cl.getMethods();//获取某个类里面的所有的公共的方法

for(Mwww.baiyuewang.netethodm:ms){

mmap.put(m.getName(),m.getGenericReturnType().toString());//遍历出所有的方法,将方法名和返回类型存在静态的map中(缓存)

}

clazzs=mmap;

typeMap.put(clazz,mmap);

}

returnclazzs.get(method);

}



}

复制代码

代码部分应该没啥要说的了吧,注释已经写的很清楚了,剩下的就需要参照jdk文档了。那么现在来扯扯代码之外的技术话题。







一,九个活动,一人一周



其实是这样的。我的新公司,是给电信做运营支撑的,每到节假日都会做一些送流量送话费的活动。这一次,是针对八月份的里约奥运会来的,给新疆那边做了九个活动,什么奥运游泳,奥运射击等等等、、反正就九个了。



本来吧这跟我是一点关系搭不上,但是后来出了点小意外,,离上线还要一周多点的时间,九个活动大家已经开发的快差不多了,突然接到上级的通知开个紧急会议,说活动需要整改,,,说是生产环境为了安全考虑,web应用不可以直接访问数据库,数据库需要放在内网服务器。目前的解决方案就是开发一套内网应用,专门用来做数据库读写操作,然后对外提供接口,供给web应用访问。然后领导接对我说,现在公司大部分人都投入到这期的活动中了,都抽不出时间,有几个新手,也不太放心他们去弄,所以这个艰巨的任务就交给你了,一周能搞定吧?然后我就恩啊恩啊的答应了。



下了班之后,突然觉得有点不对劲!一周!!!九个活动的数据读写操作!!瞬间崩溃掉了,一周时间还不够我了解九个活动业务上的需求呢。于是赶紧去找领导问问能不能通过其他方式解决,就比如在最外层加个反向代理服务器做个请求转发什么的,这样就不用去改代码了。但是领导的回复是不行。。好吧,只能认栽了。



二,为什么要用反射



第二天过来,向参与活动开发的同事打听了一下情况。一开始是一点思路都没,后来有人提议,让他们提供sql,这样会大大减少我这边的工作量。然后我问了下,发现大部分活动是用jfinal写的,这样的话我就可以直接把他们的Dao层的文件直接拷贝过来了。接下来要做的就是写接口,将方法一一对应起来。于是新的问题来了,每个活动,数据库读写最少有15个方法以上,而且每个方法传的参数都不一样,开发的时候也没有考虑过要整合的问题,所以根本就不存在什么继承,什么多态。这就意味着,我要写接近200个方法与之一一对应,对于我来说,这是写代码以来,最大的灾难!告诉我,这种情况下,除了用反射,我还能怎么办?要我码两百个方法,干脆让我去shi吧。。。



三,性能堪忧



三天之后,算上换行,还有搬砖部分的,累积不超过800行代码结束了这场灾难。接下来的几天,是跟几个开发活动的同事调接口,然后就匆匆上线了。测试的时候感觉还行,但是上线之后,感觉活动打开特别卡。然后我们公司运维查了下服务器性能情况,发现部署后台接口的那台服务器CPU占用率飙到了90%以上。妈的,灾难又来了,肯定是程序出问题了,之前了解过jvm性能监控方面的一些知识,然后百度了一下利用jstack命令打印出堆栈信息分析是那部分代码出的问题。然而,堆栈信息是打印出来了,但是完全看不懂(希望能有个大神指点一下)。没办法最后只好一段代码,一段带代码的测了(感觉应该有更好的方法)。虽然办法有点笨,但最后终于不负所望找到了凶手,原来是反射部分的代码。



四,优化之路



百度了一下,发现在加载类的时候,还有查找和执行方法的时候是很占资源的。想了好一会,觉着可以把这几个比较耗资源的操作缓存起来,这样的话只有在一次调用这个方法的时候比较耗资源,之后除了执行method.invoke方法以外,其他比较好资源的参数,可以直接从缓存中区,应该能缓解一部分压力了吧。光想没用,不如干起来。完了以后测试了一下,执行时间比原来快了接近10倍,而且同一个方法调用次数越多,就越能感觉到差距。







现在项目已经上线了有一段时间了,基本没我啥事了。抽个空分享下那段时间的工作心得,顺便提醒一句,在并发量大的情况下,能不用反射尽量不用!还有,谁告诉我,这种情况下,除了用反射,我还能怎么办???

献花(0)
+1
(本文系thedust79首藏)