`
jakoes
  • 浏览: 69000 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

spring源码分析-controller的线程安全

阅读更多
大家都知道,struts1.2由于是线程安全的,每一个请求都去实例化一个action,造成大量并发时的资源浪费。
  struts2在这一点上做了改进,每个action都是一个singleton,所有的请求都是请求同一个action实例。这样在一定程度上能节约资源,但又有安全问题。最常见的就是在action中声明有块状的实例变量,因为这一点是不被提倡的。如果一定要声明,那一定要加上同步块。
  那么在spring mvc中的controller是不是线程安全的呢?答案是否定的。controller在默认情况下也是非线程安全的,我们来看看源码:

 * @author John A. Lewis
 * @author Juergen Hoeller
 * @since 2.0
 * @see ResourceAwareController
 * @see EventAwareController
 */
public abstract class AbstractController extends PortletContentGenerator implements Controller {

	[color=red]private boolean synchronizeOnSession = false;[/color]



由上面源码可知,controller默认是非安全的。


	
public void handleActionRequest(ActionRequest request, ActionResponse response) throws Exception {
		// Delegate to PortletContentGenerator for checking and preparing.
		check(request, response);

		// Execute in synchronized block if required.
                //只有synchronizeOnSession设置为true,才会同步处理请求
		if (this.synchronizeOnSession) {
			PortletSession session = request.getPortletSession(false);
			if (session != null) {
				synchronized (session) {
					handleActionRequestInternal(request, response);
					return;
				}
			}
		}

		handleActionRequestInternal(request, response);
	}



只有手工设置controller的synchronizeOnSession值为true,才会被同步处理。

因此,我们在使用spring mvc 的contrller时,应避免在controller中定义实例变量。

##### 更正 ####################################
由于在下对struts1.x的理解也来自网络,给大家带来不便,还请见谅。
经过对struts1.x源码的研读发现:
struts1.2获取action的方式是单例的,所有的action都被维护在一个hashMap里,当有请求到达时,先根据action的名称去hashMap里查找要请求的Action是否已经存在,如果存在,则直接返回hashMap里的action。如果不存在,则创建一个新的Action实例。


下面我们来分析一下源码:

请求到达ActionServlet时,首先会到达doGet()或doPost()方法,而ActionServlet转给了process()方法进行统一处理


    public void doPost(HttpServletRequest request,
               HttpServletResponse response)
        throws IOException, ServletException {

        process(request, response);

    }





而process()方法又会转给processor的process()方法进行处理

    protected void process(HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException {

        ...
        processor.process(request, response);

    }




processor的process()方法里经过一系列处理后,最后通过processActionCreate方法来返回一个具体的action实例


public void process(HttpServletRequest request,
                        HttpServletResponse response)
        throws IOException, ServletException {

        ...

        // Create or acquire the Action instance to process this request
        Action action = processActionCreate(request, response, mapping);
        if (action == null) {
            return;
        }

     ...

    }




那我们就到processActionCreate这个方法里去一窥究竟吧:
1、先获取类名
2、根据类名去map里查寻实例是否已经存在
3、如果存在,则直接返回
4、如果不存在,则创建一个新实例
5、把创建好的action放到map里备用

  
protected Action processActionCreate(HttpServletRequest request,
                                         HttpServletResponse response,
                                         ActionMapping mapping)
        throws IOException {

        // Acquire the Action instance we will be using (if there is one)
        String className = mapping.getType();//1、先获取类名 
        ...
        Action instance = null;
        synchronized (actions) {

            // Return any existing Action instance of this class
            instance = (Action) actions.get(className);//2、根据类名去map里查寻实例是否已经存在
            if (instance != null) {
                return (instance); //3、如果存在,则直接返回
            }

            // Create and return a new Action instance
            //4、如果不存在,则创建一个新实例
            instance = (Action) RequestUtils.applicationInstance(className)

            instance.setServlet(this.servlet);
            actions.put(className, instance);//5、把创建好的action放到map里
        }
        ...
        return (instance);

    }



我们再来看看actions的定义:

    /**
     * The set of Action instances that have been created and
     * initialized, keyed by the fully qualified Java class name of the
     * Action class.
     */
    protected HashMap actions = new HashMap();


结论:
struts1.2获取action的方式是单例的,所有的action都被维护在一个hashMap里,当有请求到达时,先根据action的名称去hashMap里查找要请求的Action是否已经存在,如果存在,则直接返回hashMap里的action。如果不存在,则创建一个新的Action实例。

分享到:
评论
17 楼 颓废主义 2013-11-14  
楼主敢不敢把你的原文删除了,或者把更正的内容放后边,然后附上原文,你这样误人子弟都一年了。
16 楼 fddjxllren 2012-03-23  
struts2是单例的可以改变设定作用域为scope="prototype"改为原型模式就可以避免安全问题
15 楼 fddjxllren 2012-03-23  
楼主误人子弟呀,struts1就不存在线程安全问题他所有的方法都是定义在execute里面,struts2是多线程请求的单例,所以有线程安全问题.只要不定义实例变量,静态变量,必须设定作用域为prototype,或扩长requestprocess
14 楼 citymoon2000 2011-10-16  
说反了,差点误导我了
13 楼 accpchf 2011-06-16  
现在的web mvc的请求控制器(action或controller)的实例化有这么三种,一种是作为全局对象的单例方式,第二是全局对象的prototype方式,第三种是局部对象的方式。
在用第一种方式的时候,如果把请求控制器直接暴露给开发者,那么肯定是线程不安全的,也就是说,单例的实例变量,会被多线程共享,造成不安全。所以当把请求控制器直接暴露给开发者时候,避免线程安全的解决方式之一,就是把这个全局的请求控制器设置为prototype,可是会造成额外的开销(要精打细算吗)。
第三种方式把请求的逻辑对象,“插入”到底层的请求控制器里,那个底层的请求控制器不用开发者去关注,类似webWork,因为“插入”的逻辑对象是"局部变量",所以线程安全,不过也会有开销的问题(不用那么精打细算吧)。
具体有下面几种情况:
1.servlet 的实例化是在容器里,是单例,第一种设计方式。
1.struts1的action,都会放在一个map里面管理,单例,第一种设计方式。
2.spring mvc的controller,注入到spring 的bean容器里。是单例,第一种设计方式。
3.webWork早期的版本,是基于ServletDispatcher,是继承HttpServlet,即对servlet的封装。
servlet虽然是单例,ServletDispatcher 本身不会像struts1,spring mvc那样,直接把servlet的封装暴露给开发者,而是让开发者去写好acton,ServletDispatcher 处理services方法时,调用那些acton就行了。这里就不存在servlet的线程安全问题。第三种方式。
3.webWork现在的版本(struts2)。抛弃了ServletDispatcher,而用filterDispatcher,这个filter的封装。而基于filter的封装,因为可以把请求控制器直接当成一个普通的pojo,由filter调用请求控制器(action)进来处理。所以每次处理请求,new 一次 请求控制器,就不会有线程安全的问题。第三种方式。
4.当struts2和spring整合的时候,需要注入action到spring中去,spring默认的实例action的方式是单例,所以这样会有线程安全的问题,因为,struts2的acton里的实例变量,经常是用来接收http请求参数的,所以配置的时候,一定要设置成prototype。第二种设计方式。
5.不过,如果用了struts2-spring 插件的时候,这个插件对action的实例,默认是prototype,不需要设置。第一种设计方式。但是可以设置为prototype。第二种设计方式。

12 楼 accpchf 2011-06-16  
楼主,误人子弟
11 楼 cppmayi 2010-07-07  
别误人子弟,赶紧修改。struts2是多例
10 楼 wnick 2010-07-07  
jakoes 写道
  大家都知道,struts1.2由于是线程安全的,每一个请求都去实例化一个action,造成大量并发时的资源浪费。
  struts2在这一点上做了改进,每个action都是一个singleton,所有的请求都是请求同一个action实例。这样在一定程度上能节约资源,但又有安全问题。最常见的就是在action中声明有块状的实例变量,因为这一点是不被提倡的。如果一定要声明,那一定要加上同步块。
 


反了哦
struts2 大部分是每次实例化
struts1 是单粒的
9 楼 yunzhu 2010-07-07  
lz误人子弟啊,我这种菜鸟就是被这么误掉的,哈哈
8 楼 lydawen 2010-07-07  
struts1来一个请求,通过key(action)到actionMap里找,找到null就添加一个创建,否则直接使用。
7 楼 zy2419 2010-07-07  
我就说怎么一看感觉变扭。。
6 楼 rentianchou 2010-07-07  
aws 写道
LZ搞反了吧

struts1是单例提供服务,请求数据绑定在actionform里,form当做参数传入调用方法,不用实例变量就不会出现并发问题---spring mvc的contrller也是这样的模式

struts2是每次创建新的实例,其请求变量是绑定在action的实例变量里面,用spring管理S2的action时,因为spring的bean默认是只创建一个实例,所以必须设定作用域为prototype才行



我说也是LZ搞反了
5 楼 love_ai87 2010-07-07  
果然是反了
4 楼 wangr1984 2010-07-06  
楼主反了额
3 楼 aws 2010-07-06  
LZ搞反了吧

struts1是单例提供服务,请求数据绑定在actionform里,form当做参数传入调用方法,不用实例变量就不会出现并发问题---spring mvc的contrller也是这样的模式

struts2是每次创建新的实例,其请求变量是绑定在action的实例变量里面,用spring管理S2的action时,因为spring的bean默认是只创建一个实例,所以必须设定作用域为prototype才行
2 楼 hepeng555 2010-07-06  
struts1 貌似是单实例的 所以会有线程安全问题
struts2 貌似是每个请求都有一个实例 所以不会有线程安全的问题
1 楼 waitingmyself 2010-07-06  
引用
大家都知道,struts1.2由于是线程安全的,每一个请求都去实例化一个action,造成大量并发时的资源浪费。
  struts2在这一点上做了改进,每个action都是一个singleton,所有的请求都是请求同一个action实例。


struts1.2不了解
struts2怎么会是所有的请求都是请求同一个action实例

相关推荐

    官方原版源码 spring-framework-5.2.9.RELEASE.zip

    1. **设计模式实践**:Spring源码中大量运用了工厂模式、单例模式、观察者模式等设计模式,学习源码能加深对设计模式的理解。 2. **性能优化**:通过对源码的学习,开发者可以了解Spring如何进行性能优化,如缓存、...

    spring-framework-3.2.1.RELEASE 源码

    3. **深入Spring MVC**:分析`DispatcherServlet`的请求处理流程,以及`HandlerMapping`和`HandlerAdapter`的角色。 4. **探究数据访问模块**:查看Spring如何与JDBC、ORM框架集成,以及事务管理的实现。 5. **注解...

    spring源码关键地方

    标题中的“spring源码关键地方”指的是一项关于Spring框架核心源码的深入解析。Spring是Java企业级应用开发中最常用的框架之一,它的源码分析对于开发者来说具有极高的学习价值,可以帮助理解其工作原理,提升开发...

    Spring3.x 企业级应用开发源码库文件1

    5. **源码分析**:通过研究Spring3.x的源码,开发者可以学习到如何设计和实现一个强大的、灵活的框架。源码中的注释和设计模式的使用,可以帮助理解Spring如何处理各种常见的编程挑战,如并发、线程安全和资源管理。...

    java源码程序-ov

    【Java图书管理系统源码解析】 本项目是一个基于Java语言开发的图书馆管理系统,是某大学生的毕业设计作品。作为学习和研究的资源,它提供了一整套的源代码、系统说明和程序结构文档,对于深入理解Java编程以及软件...

    springwebflux的demo

    **Spring WebFlux 概述** Spring WebFlux 是 Spring Framework 的一部分,它引入了一种反应式编程模型,用于构建高度可伸缩、非阻塞的 Web ...通过阅读和分析项目源码,你将掌握Spring WebFlux的核心概念和实践技巧。

    mybatis-spring.rar_societyx6y_spring-mybatis

    2. 创建SqlSessionTemplate:SqlSessionTemplate是Spring封装的SqlSession,提供了线程安全的操作,避免了手动管理和关闭SqlSession。 3. 映射Mapper接口:MyBatis的Mapper接口可以直接在Spring中作为bean使用,...

    精通spring 源代码

    10. **源码分析**:深入阅读Spring源码,可以帮助我们理解其内部设计思想,如事件驱动、设计模式的应用(如单例、工厂、装饰者等)、类加载机制以及线程安全等Java编程基础。 以上只是Spring框架中部分关键知识点的...

    JAVA 开发整站程序EasyJF官网全站源码-easyjfcom-src

    10. **源码分析**:通过分析EasyJF官网的源码,开发者可以学习到实际项目中的最佳实践,以及如何将EasyJF框架应用到实际项目中。 11. **版本控制**:源码可能使用Git或其他版本控制系统管理,学习如何使用这些工具...

    Java项目学习库,SprintBoot源码解析

    在"java-study-master"这个压缩包中,可能包含了上述知识点的实践示例和详细讲解,包括代码结构、配置文件、源码分析等,可以帮助学习者深入理解Java和SpringBoot的使用。通过系统地学习和实践,开发者可以提升自己...

    基于java的开发源码-论坛系统 JForum.zip

    JForum的源码分析可以帮助开发者了解如何使用Java进行Web开发,特别是对于MVC(Model-View-Controller)设计模式的应用。该项目可能采用了Servlet和JSP技术来处理HTTP请求和展示视图,使用了JDBC来与数据库交互,还...

    基于java的开发源码-论坛系统巡云轻论坛.zip

    8. **多线程和并发**:考虑到论坛的高并发访问,源码中可能会使用到多线程和并发控制技术,如synchronized关键字、Lock接口等,来保证数据的一致性和服务的高可用性。 9. **缓存技术**:为了提高性能,论坛系统可能...

    基于java的开发源码-版的酒店系统,貌似完整.zip

    【标题】:基于Java的酒店管理系统源码分析 在IT行业中,Java是一种广泛使用的编程语言,尤其在企业级应用开发中占据着主导地位。本篇文章将深入探讨一个基于Java的酒店管理系统源码,旨在帮助开发者了解如何利用...

    spring源代码

    Spring框架是Java开发中不可...通过深入研究Spring的源代码,你可以学习到设计模式的应用,如工厂模式、单例模式、代理模式等,以及如何优雅地处理并发、线程安全等问题。这将极大地提高你的编程水平和解决问题的能力。

    基于Java的实例源码-手机短信项目源码.zip

    通过分析和研究这个项目源码,我们可以深入掌握Java编程基础、网络通信技术以及可能涉及的短信服务API使用。 1. **Java编程基础**: 项目中的源码展示了Java面向对象编程的基本原则,包括类的设计、对象的创建与...

    cms源码java-Kaya-CMS:开源基于Java的CMS

    Kaya-CMS可能使用Spring Security或Apache Shiro等组件实现用户认证和授权,确保内容的安全访问。 6. **模块化设计**:为了方便功能扩展,Kaya-CMS可能会采用模块化设计,将功能拆分为独立的组件,便于单独开发和...

    java源码医疗-medigy-java:开源医疗应用框架套件

    **Java源码医疗-Medigy Java:开源医疗应用框架套件** Medigy Java是一个专为医疗行业设计的开源应用框架套件,它基于Java技术,提供了丰富的功能和工具,以帮助开发者快速构建高效、安全、合规的医疗信息系统。在...

    spring-boot-study:SpringBoot框架源码实战(已更新到springboot2版本实现)〜基本用法,Rest,Controller,事件监听,连接数据库MySQL,jpa,redis集成,mybatis集成(声明式与xml两种方式〜对应的添删查改功能),日志处理,devtools配置,拦截器用法,资源配置读取,测试集成,网络层实现请求映射,安全安全验证,rabbitMq集成,kafka集成,分布式id生成器等。实战:https:github.comhemin1003yfax-pare

    新增全新的springboot2的框架技术点(代码位于当前仓库的spring-boot2-study目录下) 基于springboot 2.0.6.RELEASE版本实现的代码演示集合,欢迎使用star / fork 新子项目列表 介绍Springboot2【自动化单元测试】的...

    基于Java的源码-毕业设计_员工管理系统含文档.zip

    Spring Security或Apache Shiro等安全框架可以用于实现这一目标。 7. 文档部分:通常会包含系统设计文档、需求分析、数据库设计、使用手册等,帮助开发者理解整个系统的架构和功能。 在实际开发过程中,可能会采用...

    Struts 1.2源码

    这个源码分析将帮助我们深入理解Struts 1.2的工作原理和内部机制。 1. **MVC架构** - Model:在Struts 1.2中,模型通常由JavaBean或业务服务对象(Business Service Objects, BSOs)组成,负责处理业务逻辑。 - ...

Global site tag (gtag.js) - Google Analytics