Spring MVC 性能提升

关键字: Spring   #Spring    
这几天在做公司内部SpringMVC的培训,培训之余看了看大家的代码,总感觉一个很不爽的地方,就是在每一个控制器的执行方法里,总要写这样一段代码:
代码1:
  1. Map model = new HashMap();
  2. model.put("yourKey", "yourObject");
  3. ModelAndView mv = new ModelAndView("yourPage", model);
  4. ...
  5. ...
  6. return mv;
每个请求就要new 一个Map和一个ModeAndView对象,这样如果请求多,就在不停的做new操作。new操作对JVM来说开销算是比较大的,所以尽量少建新对象。
在上面的例子中我们用ModelAndView的构造函数是public ModelAndView(String viewName, Map model),打开该构造函数的源码:
代码2
  1. public ModelAndView(String viewName, Map model) {
  2.      this.view = viewName;
  3.      if (model != null) {
  4.           getModelMap().addAllObjects(model);
  5.      }
  6. }
  7. //getModelMap()的代码:
  8. public ModelMap getModelMap() {
  9.      if (this.model == null) {
  10.           this.model = new ModelMap();
  11.      }
  12.      return this.model;
  13. }

可以看出我们在java 代码1中创建的Map,在被提取值以后就没有什么用了。所以在Controller里面创建Map对象是冗余操作。
代码1应该如下写:
代码3
  1. ModelAndView mv = new ModelAndView();
  2. Map model = mv.getModelMap();
  3. model.put("yourKey", "yourObject");
  4. ...
  5. ...
  6. return vm;
这样一来就少创建了一个对象,节省了一点点开销。
可是还是每次都要创建ModelAndView新实例,如果一个网站的日访问量是10万(当然,访问理大的网站都会考虑用静态页面的方法),那么一天这个JVM就要创建10万个ModelAndView实例。这样的开销就很大了。

一般的解决办法就是让ModelAndView能够循环利用,要想循环利用ModelAndView就要有一个Pool,在我们需要可以通过Pool.get方法来取出ModelAndView实例,在不需要时在调用Pool.release(ModelAndView)把它放回。需要进取出总是很好办的,问题在什么时候可以调用release方法来释放。解决这个问题只能看SpringMVC的源码,看看有没有解决办法。
最笨方法的就是顺藤摸瓜,每一个请求到来都要先到DispatchServlet的doService。打开源码找到这个方法,发现也没有什么了不起的地方,可是发现一个醒目的片段:
  1. try {
  2.      doDispatch(request, response);
  3. }
  4. finally
看来重要工作还在doDispatch中,那么就再找到doDispatch。
在doDispatch方法的前半部分是得到Controller返回的ModelAndView对象,后半部分是做显示处理,其中有这样一个显赫的代码段:
 
  1. // Did the handler return a view to render?  
  2. if (mv != null && !mv.wasCleared()) {  
  3.     render(mv, processedRequest, response);  
  4. }  
在被调的render方法里,就可以看出当render方法执行完后,ModelAndView对象已经不会再被使用,唯一能用到它的就是垃圾回收器了。(如果不信,你可以继续往下看, 以后工作都在View的子类里跑)
所以在render方法结束以后,再把ModelAndView对象放入缓存是正确的。我们可以继承DispatchServlet,然后把render方法重写,再用一个List作为简单的缓存池,实现如下:
代码4
 
  1. public class CustomDispatchServlet extends DispatcherServlet {  
  2.       
  3.     private static List  modeAndViews =  new ArrayList ( 20);  
  4.       
  5.     static{  
  6.         for(int i = 0; i < 20; i++){  //缓存量为20  
  7.             modeAndViews.add(new ModelAndView());  
  8.         }  
  9.     }  
  10.       
  11.     public void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response)  
  12.     throws Exception{  
  13.         super.render(mv, request, response);  
  14.         releaseModelAndView(mv);  
  15.     }  
  16.       
  17.         //回收ModelAndView  
  18.     private void releaseModelAndView(ModelAndView mv){  
  19.         mv.clear();  
  20.         mv.getModelMap().clear();  
  21.         synchronized(modeAndViews){  
  22.             modeAndViews.add(mv);  
  23.         }  
  24.     }  
  25.       
  26.         //取ModelAndView  
  27.     public static ModelAndView getModeAndView(){  
  28.         synchronized(modeAndViews){  
  29.             if(modeAndViews.size() > 0)  
  30.                 return modeAndViews.remove(0);  
  31.             else  
  32.                 return new ModelAndView();  
  33.         }  
  34.     }  
  35.       
  36. }  
当然你的web.xml的配置应改为:
代码5
 
  1. <servlet>  
  2.     <servlet-name>test</servlet-name>  
  3.         <servlet-class>your.package.CustomDispatchServlet</servlet-class>  
  4.     <load-on-startup>1</load-on-startup>  
  5. </servlet>  
然后你Controller里的执行代码也应改成如下:
代码6
 
  1. ModelAndView mv = CustomDispatchServlet.getModeAndView();  
  2. mv.setViewName("yourPage");  
  3. mv.getModel().put("attribute""yourObject");  
  4. ...  
  5.        ...  
  6. return mv;  
整个完成以后,测试起来屡试不爽。
整个下来,没有做太大的改到,也降低了开销。

还有一点要提醒一下,如果你用JSP做为页面,请不要用在ModelAndView的Map里放什么东西,这样Spring要做很多无用功,如果有东东全放入HttpServletRequest中,要想研究的话可以看看InternalResourceView的方法renderMergedOutputModel。

引用位置:http://acf.javaeye.com/blog/143987
 
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值