`
acf
  • 浏览: 35112 次
文章分类
社区版块
存档分类
最新评论

Spring MVC 性能提升

阅读更多
这几天在做公司内部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<ModelAndView> modeAndViews = new ArrayList<ModelAndView>(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。

分享到:
评论
23 楼 bottom 2008-08-29  
在现在的JVM里,这种 lightweight object 的 pooling是performance killer. 不能用!
22 楼 sunrie 2008-08-27  
就是嘛,楼主测试过new对象的速度吗?
21 楼 Joo 2008-08-27  
同意楼上,最好的优化就是不优化...这废话谁说的来着?
另外各位如何评判一个对象是heavy还是light? Connection相对于Map来说创建比较消耗资源体现在什么地方?
20 楼 javalover 2008-08-26  
这是想当然performance tuning的一个很好的例子。
performance tuning的第一条原则就是不要想当然,通过测试数据来说话。
19 楼 laiseeme 2008-08-08  
呵呵  我看lz整得也挺好 看了一圈了解了下springMVC内部的东西

不过这种优化确实没必要  就像上面人说的  同步开销要大得多

一般对象池用在大开销的重量级对象上
轻量级的给jvm处理就可以了,如果jvm连这点处理能力都没有
哪sun可以关门了
18 楼 dakulaliu 2008-08-07  
魔力猫咪 写道
恩。new并不一定是性能的问题所在。要是按你的说法Struts2这类每次请求都要新建Action的框架要慢死的。


严重同意!!!!!!!!!!!!
17 楼 dengyin2000 2008-06-05  
zgd 写道
在新版本的java里面,同步比gc慢
所以以前很多framework里面都有pool的设定,现在都取消了
现在只有一些数据库连接等IO资源做pool以外,基本的数据class已经都不作pool了


pool 一般用在创建很大消费的对象时才用的。 比如 connection, tapestry的page。 像new HashMap这样的 是没有必要的。
16 楼 xzs 2008-06-05  
zgd 写道
以前很多framework里面都有pool的设定,现在都取消了


很多?可否举些例子?
15 楼 zgd 2008-06-05  
在新版本的java里面,同步比gc慢
所以以前很多framework里面都有pool的设定,现在都取消了
现在只有一些数据库连接等IO资源做pool以外,基本的数据class已经都不作pool了
14 楼 惊鸿逝水 2008-06-05  
LZ,你应该更仔细才对,你会发现有很多很多对象没缓存,这下你会惊出一身的冷汗……
因为你发现你会变得很忙很忙
13 楼 slaser 2008-06-05  
建议lz不要用web框架,直接上servlet,效率最高。
12 楼 lzmhehe 2008-06-05  
downpour 写道
有时间花在这种无关痛痒的事情上面,还不如看看如何通过调整你Web服务器的配置参数来进行优化。

不懂,为什么很多人都无法找到问题的主要方面和次要方面。



在一个项目中没有调整 jvm 和tomcat 的参数
出现莫名其妙的事情,血的教训啊

11 楼 魔力猫咪 2008-06-05  
wangneng_001 写道
魔力猫咪 写道
恩。new并不一定是性能的问题所在。要是按你的说法Struts2这类每次请求都要新建Action的框架要慢死的。

不是每次请求都会创建哦,仅仅是第一次请求吧。

是每次请求都创建新的。Struts2的Action师从Webwork。Action里面可以写私有属性的。如果是单例,那么这些私有属性就会因为并发而混乱,所以必须每次请求一个新Action对象。放心,JVM会马上把它丢掉的。
10 楼 wangneng_001 2008-06-05  
魔力猫咪 写道
恩。new并不一定是性能的问题所在。要是按你的说法Struts2这类每次请求都要新建Action的框架要慢死的。

不是每次请求都会创建哦,仅仅是第一次请求吧。
9 楼 downpour 2008-06-05  
有时间花在这种无关痛痒的事情上面,还不如看看如何通过调整你Web服务器的配置参数来进行优化。

不懂,为什么很多人都无法找到问题的主要方面和次要方面。
8 楼 chaos_1981 2008-06-05  
数据库用连接池有必要,这个没什么必要吧

synchronized 在大并发的情况下可能会引起排队情况
7 楼 dennis_zane 2008-06-05  
这完全是想当然式的优化
6 楼 魔力猫咪 2008-06-05  
恩。new并不一定是性能的问题所在。要是按你的说法Struts2这类每次请求都要新建Action的框架要慢死的。
5 楼 fujohnwang 2008-06-05  
有点儿反其道而行之的感觉了
4 楼 linhong_1001 2008-06-05  
同意楼上的,同步做得不好的话开销更大,不知道本贴的楼主有没有做过真正的压力测试和性能测试,凭什么认为那样“重复利用MaV对象”就高效了,现代垃圾回收器可是比你想象的高效和稳定,我觉得不要凭感觉说话,还是做了测试之后再做性能改善,也学你的项目的性能瓶颈并不是想当然的在某个地方。

相关推荐

    Spring MVC 4.2.3

    在"Spring MVC 4.2.3"版本中,我们看到了一系列的功能改进和优化,以提升开发效率和应用性能。 首先,让我们深入了解Spring MVC的基础架构。模型(Model)负责存储应用的数据,视图(View)用于展示这些数据,而...

    spring mvc 4.0

    在Spring MVC 4.0版本中,它引入了许多改进和新特性,以提升开发效率和应用程序的性能。 1. **依赖注入**:Spring MVC 4.0继续支持Spring框架的核心功能,依赖注入(DI),允许开发者通过配置来管理对象及其依赖...

    Mastering Spring MVC 4(2015.09)源码

    首先,Spring MVC 4基于Servlet 3.0规范,这意味着它可以利用异步处理能力,提高了Web应用的性能。通过AsyncSupport和AsyncConfigurer接口,开发者可以轻松地创建异步控制器,处理高并发场景。 控制器(Controller...

    开发Spring MVC应用程序补充—程序源码下载.rar_spring_spring mvc_spring mvc 源码_sp

    10. **源码分析**:通过对Spring MVC源码的阅读和理解,学习其内部工作原理,提升问题排查和性能调优的能力。 以上就是基于提供的信息推测的Spring MVC相关知识点。通过学习和实践这些内容,开发者可以系统地掌握...

    《精通Spring MVC 4》源码

    通过仔细阅读和分析这些源代码,开发者不仅可以提升对Spring MVC框架的理解,还能学习到设计模式、性能优化和最佳实践,从而在实际项目中更有效地应用Spring MVC。无论是初学者还是经验丰富的开发者,都应该充分利用...

    Spring MVC Cookbook(PACKT,2016).pdf

    15. **性能优化**:了解如何缓存结果、使用CDN、优化视图渲染速度等,提升Spring MVC应用的性能。 通过这本书,开发者可以系统地学习Spring MVC的各个方面,提升在实际项目中的应用能力。无论你是初学者还是有经验...

    spring、 spring mvc、 mybatis 开发的java客户关系管理系统,前端采用easyui编写.zip

    7. 性能优化:为了提升系统性能,可能需要实施缓存策略(如使用Spring Cache或Redis)、数据库连接池(如Druid或HikariCP)、以及合理的数据库索引设计。 8. 扩展性与维护性:采用模块化设计,每个功能模块独立,...

    spring mvc

    8. **Interceptors**: 拦截器是Spring MVC中的一个高级特性,可以对请求进行预处理和后处理,比如登录检查、性能监控等。 9. **HandlerAdapter**: 处理器适配器负责调用控制器的方法,Spring MVC 内置了多种适配器...

    精通spring mvc 4 看透springmvc pdf 高清完全版

    总的来说,《精通Spring MVC 4:看透SpringMVC》是一本全面且深入的指南,适合有Java基础并希望提升Spring MVC技能的开发者阅读。通过学习本书,读者将能够熟练地运用Spring MVC构建高性能、可维护的Web应用程序,并...

    spring mvc mysql hibernate

    学习和掌握这三大技术,对于Java Web开发者来说至关重要,不仅能够提升开发效率,还能为构建稳定、高性能的应用打下坚实基础。在实际开发过程中,应熟练运用Spring MVC的注解驱动,理解Hibernate的懒加载和级联操作...

    spring MVC文档

    Spring MVC是Spring框架的一个核心模块,它主要用于构建Web应用程序的模型-视图-控制器(MVC)架构。...通过深入学习并实践文档中的内容,可以提升开发者在Spring MVC上的专业技能,从而更好地应对复杂的Web开发挑战。

    Spring mvc+hibernate+mysql Demo

    【Spring MVC + Hibernate + MySQL 整合详解】 在IT领域,Spring MVC、Hibernate和MySQL是构建Web应用程序的常用技术栈。Spring MVC作为Spring框架的一部分,提供了强大的MVC(Model-View-Controller)架构,用于...

    spring mvc+ajax

    将Spring MVC与Ajax结合使用,可以实现页面的异步更新,提升用户体验,同时保持服务器负载均衡。 首先,我们需要理解Spring MVC的基本工作流程。当用户发起请求时,Spring MVC的DispatcherServlet会拦截这个请求,...

    bbs.zip_Spring mvc bbs_hibernate bbs_spring mvc_spring mvc hiber

    Spring3是Spring框架的一个版本,相较于之前的版本,它在性能、可扩展性和易用性上都有所提升。在这个项目中,Spring3不仅作为Spring MVC的基础,还可能用于实现事务管理、安全控制等方面。 Spring MVC与Hibernate...

    Spring mvc整合redis实例(redis连接池)

    将Spring MVC与Redis结合,可以有效提升应用的响应速度和数据处理能力。本文将详细介绍如何在Spring MVC中整合Redis,并利用连接池来优化性能。 首先,我们需要引入Redis的相关依赖。在Maven项目中,可以在pom.xml...

    spring mvc+spring+hibernate+bootstrap+mysql 考勤及薪酬管理系统

    《基于Spring MVC+Spring+Hibernate+Bootstrap+MySQL的考勤及薪酬管理系统详解》 在现代企业信息化管理中,考勤和薪酬管理是至关重要的部分,它们直接影响到员工的工作积极性和公司的运营效率。本文将深入探讨一个...

Global site tag (gtag.js) - Google Analytics