spring中scope的singleton和prototype区别

scope="singleton"/>

  •   这里的scope就是用来配置spring bean的作用域,它标识bean的作用域。在spring2.0之前bean只有2种作用域即:singleton(单例)、non-singleton(也称prototype),Spring2.0以后,增加了session、request、global session三种专用于Web应用程序上下文的Bean。因此,默认情况下Spring2.0现在有五种类型的Bean。当然,Spring2.0对Bean的类型的设计进行了重构,并设计出灵活的Bean类型支持,理论上可以有无数多种类型的Bean,用户可以根据自己的需要,增加新的Bean类型,满足实际应用需求。
  •   1、singleton作用域
  •   当一个bean的作用域设置为singleton, 那么Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。换言之,当把一个bean定义设置为singleton作用域时,Spring IOC容器只会创建该bean定义的唯一实例。这个单一实例会被存储到单例缓存(singleton cache)中,并且所有针对该bean的后续请求和引用都将返回被缓存的对象实例,这里要注意的是singleton作用域和GOF设计模式中的单例是完全不同的,单例设计模式表示一个ClassLoader中只有一个class存在,而这里的singleton则表示一个容器对应一个bean,也就是说当一个bean被标识为singleton时候,spring的IOC容器中只会存在一个该bean。
  •   配置实例:
  •   
  •   或者
  •   
  •   2、prototype
  •   prototype作用域部署的bean,每一次请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)都会产生一个新的bean实例,相当与一个new的操作,对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责,容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责。让Spring容器释放被singleton作用域bean占用资源的一种可行方式是,通过使用bean的后置处理器,post-processor,该处理器持有要被清除的bean的引用。)
  •   配置实例:
  •   scope="prototype"/>
  •   或者
  •   singleton="false"/>

     

    scope="prototype">



    singleton模式指的是对某个对象的完全共享,包括代码空间和数据空间,说白了,如果一个类是singleton的,假如这个类有成员变量,那么这个成员变量的值是各个线程共享的(有点类似于static的样子了),当线程A往给变量赋了一个值以后,线程B就能读出这个值。因此,对于前台Action,肯定不能使用singleton的模式,必须是一个线程请求对应一个独立的实例。推而广之,只要是带数据成员变量的类,为了防止多个线程混用数据,就不能使用singleton。对于我们用到的Service、Dao,之所以用了singleton,就是因为他们没有用到数据成员变量,如果谁的Service需要数据成员变量,请设置singleton=false。 有状态的bean都使用Prototype作用域,而对无状态的bean则应该使用singleton作用域。

    在 Spring2.0中除了以前的Singleton和Prototype外又加入了三个新的web作用域,分别为request、session和 global session。如果你希望容器里的某个bean拥有其中某种新的web作用域,除了在bean级上配置相应的scope属性,还必须在容器级做一个额外的初始化配置。即在web应用的web.xml中增加这么一个ContextListener: org.springframework.web.context.request.RequestContextListener 以上是针对Servlet 2.4以后的版本。比如Request作用域。

 

"personAction" scope="prototype" class="quickstart.action.PersonAction">
        "personService" />
在配置文件中,bean默认是单例模式,应用服务器启动后就会立即创建bean,以后就可以重复使用。
这带来一个问题,bean的全局变量被赋值以后,在下一次使用时会把值带过去。也就是说,bean是有状态的。
在web状态下,请求是多线程的,全局变量可能会被不同的线程修改,尤其在并发时会带来意想不到的bug。
而在开发时,访问量很小,不存在并发、多线程的问题,程序员极有可能会忽视这个问题。
所以在配置action bean时,应使用scope="prototype",为每一次request创建一个新的action实例。这
符合struts2的要求,struts2为每一个request创建一个新的action实例。当request结束,bean就会被jvm
销毁,作为垃圾收回。
当然,也可以设置scope="session",也能避免web中action的并发问题,只为当前用户创建一次bean,直至
session消失。在这种情况下,对当前用户而言,bean是有状态的。好处就是少创建bean的实例,有那么一
点点性能的提升
应用场景:
    1. 多数情况下应使用prototype
    2. 若用户不多,且频繁操作(频繁使用action),硬件一般,可以考虑session,兴许还能提升一点点性能。

最近突然想到一个问题

 

以前在用struts2(注解)+spring

struts的action拖给spring管了(spring的bean在Ioc容器范围内默认都是singlen的),但是没有加@scope("prototype")却从来没有出现过线程安全问题。

而一年前还在学校时做ssh2(没用注解)练习时,不在bean后加prototype都会出现线程安全问题,当时所有的action后都加了scope=prototype。

难道注解和不用注解,struts2创建action的方式不一样?

于是做了个测试

Java代码   收藏代码
  1. public class TestAction extends BaseAction {  
  2.     @Autowired  
  3.     private UserService userService;  
  4.     @Action("test")  
  5.     public String test() throws Exception {  
  6.         System.out.println("action HashCode:"+this.hashCode());  
  7.         userService.getUserName();        
  8.         return "success";  
  9.     }  
  10. }  
Java代码   收藏代码
  1. @Service  
  2. public class UserService {  
  3.  public void getUserName(){  
  4.   System.out.println("service HashCode:"+hashCode()); }  
  5. }  

 连续运行3次发现输出:

Java代码   收藏代码
  1. action HashCode:9928297  
  2. service HashCode:32262619  
  3. action HashCode:13620718  
  4. service HashCode:32262619  
  5. action HashCode:19792917  
  6. service HashCode:32262619  

 输出结果说明 每次的action是不一样的

而每次的service是同一个也就是单例的

(难道action并没有交个spring托管)

又把以前在学校做的老项目(纯xml)拿来 把以前的scope="prototype"去掉

发现action确实是单例的   再加上scope="prototype"后action不是单例了

 

所以struts2(注解) 在和spring集成时action默认是new的,不用注解spring扫描action的话也是用的new。

而非注解时如果把action加入bean的话默认是单例的。

所以如果大家struts2是用注解的话就不需要在action上加@scope("prototype")了;

 

 

 

当指定struts.objectFactory为spring时,struts2框架就会把bean转发给spring来创建,装配,注入。但是bean创建完成之后,还是由struts容器来管理其生命周期。配置方式:

(1)struts.xml中:

xml 代码
  1. <constant name="struts.objectFactory" value="spring" />  

 

(2)struts.properties中:

java 代码
  1. struts.objectFactory=spring  

 

通常情况下,这样子就够了,然后在struts的action-mapping配置文件中,如下:

xml 代码
  1. <action name="user" class="com.myapp.admin.web.action.user.UserAction">action>  

即可,如果在Action中有依赖于其它的BEAN,也会被自动注入进来。这时候,Action实例是以prototype方式创建的,SPRING会为每个请求创建一个ACTION的实例。

 

在某些时候,你可能希望不仅仅让SPRING创建和装配Action对象,还希望让SPRING完全管理这些对象,如希望使用AOP或者希望使用acegi时。这时候,只需要在spring的配置文件中定义这些action 即可。如在applicationContext.xml文件中:

xml 代码
  1. <bean id="user" class="com.myapp.web.action.user.UserAction"/>  

然后在action-mapping中,指定class="user"即可。

 Struts和Spring整合方案有两种: 


   方案一: 
   使用委托方式,将struts中的Action配置到spring中,然后通过委托方式来调用Action 

方案二: 
   将spring上下文启动配置到struts中,通过struts运行来加载spring的配置以及让spring工作起来。 


   不管采用那种方案,都需要在struts的配置文件中,将spring配置进来,,目的就是当请求到达struts后,可以与spring协同工

 

singleton 是单态模式的 ,有ioc容器管理 ,当然不是线程安全的啦 ,不过所谓的线程安全也是相对的如果你的类是没有状态的, 那用singleton 的性能要高一些 ,因为只有一个实例。如果你的类是有状态的 ,那就必须显示的设置为prototype了在ssh2 项目中,struts2的action交由spring管理的时候,spring默认是singleton的,而struts2的action显然是有状 态的,所以必须显示设置为scope="prototype",prototype为原型模式,每次action请求过来都会创建一个action但是对 那些Dao的实现类推介scope="singleton" ,因为这些类没有状态,用singleton只需维护一个实例,显然性能高一些

spring Bean的作用域:

scope=singleton(默认,单例,生成一个实例) 不是线程安全,性能高

scope=prototype(多线程, 生成多个实例)

 

有状态会话bean   :每个用户有自己特有的一个实例,在用户的生存期内,bean保持了用户的信息,即“有状态”;一旦用户灭亡(调用结束或实例结束),bean的生命期也告结束。即每个用户最初都会得到一个初始的bean。

无状态会话bean   :bean一旦实例化就被加进会话池中,各个用户都可以共用。即使用户已经消亡,bean   的生命期也不一定结束,它可能依然存在于会话池中,供其他用户调用。由于没有特定的用户,那么也就不能保持某一用户的状态,所以叫无状态bean。但无状态会话bean   并非没有状态,如果它有自己的属性(变量),那么这些变量就会受到所有调用它的用户的影响,这是在实际应用中必须注意的

 

参考链接:http://blog.arganzheng.me/posts/spring-bean-scopes.html

你可能感兴趣的:(SSH,运维,设计模式,web.xml)