`

[Spring]并发访问bean出错解决方案,Spring中Bean的生命周期。

阅读更多

项目准备交付了,却出现了一个致命的问题:

 

项目场景:有一个核心业务类--根据个人编号,调用各种数据进行运算。

 

出现问题:A用户和B用户同时访问出现乱码错误,并且偶尔出现,A提出请求的时候返回B的结果。

 

重现错误:因为没有测试用例,项目几乎裸奔。所以用js模拟用户频繁请求,一下是html测试代码:

 

<html>
<head><title> New Document </title>
</head>
<body>
<form id="form1" name="form1" method="post" action="PreCompe.action">
        <label>个人编号:
          <input name="perscode" type="text" id="perscode"  value="" size="50"  style="height:25px; width:250px"/>
        </label>
</form>
<form action="#" id="form2" name="form2">
<input type="button" value="开始" name="btnStart"/>
<input type="button" value="重置" name="btnReset"/>
<input name="txt1" type="text" value="0" size="12"/>
</form>
</body>
</html>
<script language="JavaScript" type="text/javascript">
<!--
//获取表单中的表单域
var txt=document.form2.elements["txt1"];
var btnStart=document.form2.elements["btnStart"];
var btnReset=document.form2.elements["btnReset"]
//定义定时器的id
var id;
//每10毫秒该值增加1
var seed=0; 
btnStart.onclick=function(){
      //根据按钮文本来判断当前操作
      if(this.value=="开始"){
              //使按钮文本变为停止
              this.value="停止";
              //使重置按钮不可用
              btnReset.disabled=true;
              //设置定时器,每0.01s跳一次
              id=window.setInterval(tip,10);
      }else{
              //使按钮文本变为开始
              this.value="开始";
              //使重置按钮可用
              btnReset.disabled=false;
              //取消定时
              window.clearInterval(id);
      }
}

//重置按钮
btnReset.onclick=function(){
     seed=0;
}
//让秒表跳一格
function tip(){
      seed++;
      txt.value=seed/100;
	  openWin(seed);
}
//-->
function openWin(number){
	var perscode = document.form1.perscode.value;
       window.open ("PreCompe.action?&compeopera=1&treattype=2&perscode="+perscode,"newwindow"+number,"height=600,width=800,top=400,left=400,toolbar=no,menubar=no,scrollbars=no, resizable=no,location=no, status=no");
}
</script>

 

原理很简单,测试用例复杂,所以干脆就直接模拟很多用户每一秒钟请求一次,肯定会有并发发生。然后是多台机器同时访问。

 

结果:控制台显示,一个业务类实例没有完成,另外一个实例已经开始。

 

BUG分析:业务类一开始实例化后,存在于内存,多个请求调用产生交叉。

 

解决方法:

 

<bean id="builder" class="com.medical.domain.medcompe.impl.ConcreateBuilder" singleton="false">

 

 

附上引自:http://blog.163.com/tangyang_personal/blog/static/46229613200832235353419/的一个教程。

 

Spring中Bean的生命周期 在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就是预设为每一个Bean的别名只能维持一个实例,而不是每次都产生
一个新的对象
使用Singleton模式产生单一实例,对单线程的程序说并不会有什么问题,但对于多线程的程序,就必须注意安全(Thread-safe)的议题,防止多个线程
同时存取共享资源所引发的数据不同步问题。
然而在spring中 可以设定每次从BeanFactory或ApplicationContext指定别名并取得Bean时都产生一个新的实例:例如:
<bean singleton="false">
在spring中,singleton属性默认是true,只有设定为false,则每次指定别名取得的Bean时都会产生一个新的实例
一个Bean从创建到销毁,如果是用BeanFactory来生成,管理Bean的话,会经历几个执行阶段:
    1:Bean的建立:
          有BeanFactory读取Bean定义文件,并生成各个Bean实例
    2:属性注入:
          执行相关的Bean属性依赖注入
    3:BeanNameAware的setBeanName():
          如果Bean类有实现org.springframework.beans.BeanNameAware接口,则执行它的setBeanName()方法
    4:BeanFactoryAware的setBeanFactory():
          如果Bean类有实现org.springframework.beans.factory.BeanFactoryAware接口,则执行它的setBeanFactory()方法
    5:BeanPostProcessors的ProcessBeforeInitialization()
          如果任何的org.springframework.beans.factory.config.BeanPostProcessors实例与Bean实例相关。则执行BeanPostProcessors实例
          的processBeforeInitialization()方法
    6:initializingBean的afterPropertiesSet():
          如果Bean类已实现org.springframework.beans.factory.InitializingBean接口,则执行他的afterProPertiesSet()方法
    7:Bean定义文件中定义init-method:
          可以在Bean定义文件中使用"init-method"属性设定方法名称例如:
          <bean calss="onlyfun.caterpillar.HelloBean" init-method="initBean">
          如果有以上设置的话,则执行到这个阶段,就会执行initBean()方法
    8:BeanPostProcessors的ProcessaAfterInitialization()
          如果有任何的BeanPostProcessors实例与Bean实例关联,则执行BeanPostProcessors实例的ProcessaAfterInitialization()方法
    9:DisposableBean的destroy()
          在容器关闭时,如果Bean类有实现org.springframework.beans.factory.DisposableBean接口,则执行他的destroy()方法
    10:Bean定义文件中定义destroy-method
          在容器关闭时,可以在Bean定义文件中使用"destroy-method"属性设定方法名称,例如:
          <bean destroy-method="destroyBean">
          如果有以上设定的话,则进行至这个阶段时,就会执行destroyBean()方法,如果是使用ApplicationContext来生成并管理Bean的话
          则稍有不同,使用ApplicationContext来生成及管理Bean实例的话,在执行BeanFactoryAware的setBeanFactory()阶段后,若Bean
          类上有实现org.springframework.context.ApplicationContextAware接口,则执行其setApplicationContext()方法,接着才执行
          BeanPostProcessors的ProcessBeforeInitialization()及之后的流程

0
0
分享到:
评论
1 楼 litianyu0815 2011-09-15  
唉 看不懂啊

相关推荐

    Spring容器中Bean的作用域编程开发技术共3页.pd

    单例Bean在容器启动时被创建,并在整个容器生命周期中保持唯一。 2. **原型(Prototype)作用域**:与单例相反,原型作用域的Bean每次请求都会创建一个新的实例。这适用于需要多个实例的情况,如用户会话中的对象,...

    Spring实战之Bean的作用域singleton和prototype用法分析

    这个实例在整个应用程序生命周期中被共享,无论何时请求该Bean,Spring都会返回相同的对象。例如,在提供的XML配置文件中,Bean `p1` 指定了`class="org.crazyit.app.service.Person"`,它就是一个`singleton` Bean...

    Quartz注入Spring的Bean

    2. **Spring管理Job的生命周期**:将Job类定义为Spring的Bean,这样Job实例的创建、初始化、销毁等生命周期管理就交给了Spring,而不是Quartz。这样做的好处是,Job可以轻松地利用Spring的其他服务,如数据库连接池...

    Spring并发访问的线程安全性问题.docx

    在Spring MVC中,Controller被设计为单例模式,这是为了提高性能和减少内存消耗,因为每个请求...合理的架构设计、避免实例变量、使用线程安全的数据结构以及合理配置bean的生命周期,都能帮助我们构建更健壮的系统。

    Spring bean为什么默认是单例

    这意味着无论有多少次请求获取同一个Bean,Spring容器只会创建一个实例,并且在整个应用生命周期中重复使用这个实例。这种设计决策基于性能和资源管理的考虑。 首先,让我们深入理解Spring Bean的单例模式。当一个...

    尚学堂_Spring_0600_IOC_Bean_Scope

    在这个主题下,我们将深入探讨Spring如何通过IOC管理Bean的生命周期,并且理解Bean在不同Scope下的行为差异。 首先,控制反转(IOC)是Spring框架的核心设计理念,它将对象的创建和管理的职责从应用代码中解耦出来...

    Spring5中文参考指南.zip

    Spring5的Bean容器有了改进,包括更强大的生命周期管理和事件传播机制,使得管理Bean的生命周期更加灵活。 10. **Java 8及更高版本支持** Spring5全面支持Java 8及以后的版本,充分利用了Lambda表达式、Stream ...

    spring中文参考文档

    8. **Bean的作用域**:Spring中的bean可以有多种作用域,包括单例(singleton)、原型(prototype)、请求(request)、会话(session)和全局会话(global session),每种作用域对应不同的生命周期和并发处理策略...

    spring-5.3.9-dist.zip(spring-framework-5.3.9)

    每个模块都有相应的jar包,例如`spring-context.jar`提供了上下文支持,`spring-beans.jar`处理bean的生命周期,而`spring-webmvc.jar`则用于构建Web应用程序。5.3.9版本的库可能包含了对Java 8及更高版本的支持,...

    2023最新Spring全家桶面试题-图灵徐庶

    24. Spring框架中bean的生命周期:包括实例化、初始化、销毁等。 25. Spring是如何解决Bean的循环依赖?:通过使用依赖注入和 setter方法来解决循环依赖问题。 26. Spring如何避免在并发下获取不完整的Bean?:...

    SPRING面试宝典

    Spring框架中的Bean生命周期主要包括以下几个阶段: 1. **实例化**:创建Bean实例。 2. **依赖注入**:注入依赖关系。 3. **初始化**:调用初始化方法。 4. **销毁**:调用销毁方法。 **3.8 重要的Bean生命周期...

    Spring 5源代码(spring-framework-5.3.14.zip)

    在容器和依赖注入方面,Spring 5对Bean生命周期管理进行了改进,增强了对AOP(面向切面编程)的支持。它引入了更强大的注解,如`@Profile`,使得在不同环境配置Bean变得更加容易。此外,Spring 5还加强了对JSR-330...

    SSH笔记-bean的作用域

    在Spring框架中,Bean的作用域是管理对象生命周期和作用范围的关键概念。Bean的定义通常包含在XML配置文件中,通过`&lt;bean&gt;`标签进行配置。当我们谈论"SSH笔记-bean的作用域"时,这里SSH指的是Spring、Struts和...

    Spring相关测试1全部

    选择合适的作用域有助于管理bean的生命周期和并发访问。 5. **使用外部属性文件**:Spring允许将配置信息存储在外部的properties文件中,这样可以提高代码的可维护性和灵活性。通过`@PropertySource`注解可以加载...

    axis整合spring

    2. **更好的控制反转**:通过Spring,我们可以更好地控制服务的生命周期,例如何时创建、初始化和销毁服务实例。 3. **简化事务管理**:Spring的事务管理支持可以帮助我们轻松地处理Web服务中的事务边界,确保数据...

    Spring MVC +Spring + Mybatis 构建分库分表源码

    在本项目中,Spring作为核心容器,管理着应用对象的生命周期和依赖关系。 Spring MVC是Spring框架的一部分,专门用于构建Web应用程序。它采用模型-视图-控制器(Model-View-Controller,MVC)设计模式,使得业务...

    spring-framework-5.3.20

    1. **Core Container**:核心容器包含Bean工厂(BeanFactory)和应用上下文(ApplicationContext),它们负责管理对象的生命周期和依赖注入。 2. **Data Access/Integration**:数据访问模块包括JDBC、ORM(Object-...

    Spring5.0.2 jar包

    2. **spring-beans-5.0.2.RELEASE-javadoc.jar**:此模块专注于Bean的定义和管理,包括XML配置和Java配置的处理,以及Bean的生命周期管理和属性注入。 3. **spring-context-5.0.2.RELEASE-javadoc.jar**:上下文...

    spring-5.2.3.RELEASE-dist.zip

    1. **Spring Core**:提供基础的DI容器,管理对象的生命周期和依赖关系。 2. **Spring Beans**:定义了Bean的配置方式,支持XML、注解及Java配置。 3. **Spring AOP**:实现了面向切面编程,允许定义方法拦截器和...

    HibernateSpring多数据库解决方案.doc

    在IT行业中,尤其是在Java开发领域,使用Spring框架与Hibernate整合是常见的做法,它们可以提供高效的数据访问和持久化服务。当面临多数据库的场景时,如何实现读写分离或者不同的业务逻辑对应不同的数据库,就显得...

Global site tag (gtag.js) - Google Analytics