Spring中的Singleton模式和Java中的Singleton模式

对于Spring中实现Singleton模式,是以IOC容器为单位,换句话说,一个JVM可能有多个IOC容器,而Java中实现Singleton而言,只有一个JVM。所以说,Spring中实现的Singleton模式与Java中的Singleton设计模式有点不同。

此外,springsingleton的含义是在一个spring上下文中保持单态。

所以singleton模式中,singleton的class在整个JVM中只有一个instance,Spring的Bean,你可以一个class配置多个Bean,这个class就有了多个instance。这个singleton是指在spring容器中,这个Bean是单实例的,是线程共享的。所以要求这些类都是线程安全的。也就是说,不能出现修改Bean属性的方法,当然除了设值得那些setter。只要满足线程安全,这些bean都可以用singleton。而且我们在绝大多数使用上,也是这样用的,包括dao,service。

Beanfactory是Spring初始以静态方式载入的,Spring的单例IOC是基于容器级的,所以这你都不用担心与考虑.

--应用中对象有两种,行为对象和数据对象,行为对象都要求是线程安全的!也就是允许单例的,不管是dao还是service对象,都是行为对象,行为对象不应该引用非线程安全的对象做成员量,同时在应用外部的资源(如文件,数据库连接,session)时,要先保证对这些东西的访问是做了并发控制的!

对于spring来讲,<beanscope="singleton"/>或<beansingleton="true"/>都是保证对同一sesionfactorybean是单例的,也就是所谓sessionfactory范围的.

--这是一个真实的案例,我们在项目中使用Spring和ACEGI,我之所以选择ACEGI,除了它对权限的良好控制外,

我还看好它的SecurityContextHolder,通过代码来看:

Authentication auth = SecurityContextHolder.getContext().getAuthentication();   
<script>render_code();</script>

我可以很容易在系统任意一层得到用户的信息,而不用把用户信息在参数里传来传去,(这也是struts的缺点之一)

但是我在每一次要得到用户信息的时候都写上面的一段代码,未免有些麻烦,所以我在BaseService,BaseDao里都提供了如下方法:

/**  
 * get current login user info  
 * @return UserInfo  
 */  
protected UserInfo getUserInfo()   
{   
    return getUserContext().getUserInfo();   
}   
  
/**  
 * get current login user context  
 * @return UserContext  
 */  
protected UserContext getUserContext()   
{   
    Authentication auth = SecurityContextHolder.getContext().getAuthentication();   
    return (UserContext) auth.getPrincipal();   
}   
<script>render_code();</script>

这样在其他的Service和Dao类里可以通过

super.getUserContext(), super.getUserInfo()   
<script>render_code();</script>

来得到用户的信息,这也为问题的产生提供了温床。请看如下代码:

public class SomeServece extends BaseService implements SomeInterFace     
{   
    private UserInfo user = super.getUserInfo();   
       
    public someMethod()   
    {   
       int userID = this.user.getUserID();   
       String userName = this.user.getUserName();   
       //bla bla do something user userID and userNaem   
    }   
}       
<script>render_code();</script>

这段代码在单元测试的时候不会用任何问题,但是在多用户测试的情况下,你会发现任何调用SomeService里someMethod()方法的userID和userName都是同一个人,也就是第一个登陆的人的信息。

其根本原因是Spring的Bean在默认情况下是Singleton的,BeanSomeServece的实例只会生成一份,也就是所SomeServece实例的user对象只会被初始化一次,就是第一次登陆人的信息,以后不会变了。所以BaseService想为开发提供方便,却给开发带来了风险.

正确的用法应该是这样的

public class SomeServece extends BaseService implements SomeInterFace     
{      
    public someMethod()   
    {   
       int userID = super.getUserInfo().getUserID();   
       String userName = super.getUserInfo().getUserName();   
       //bla bla do something user userID and userNaem   
    }
}

相关推荐