疯狂

STANDING ON THE SHOULDERS OF GIANTS
posts - 481, comments - 486, trackbacks - 0, articles - 1
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

注意spring, singleton不single! ?

Posted on 2010-08-30 00:41 疯狂 阅读(6901) 评论(12)  编辑  收藏 所属分类: java springweb
  spring的singleton真的会在整个应用中创建单一的对象吗?非也,他只会在内部springframework的一个applicationContext上下文中保持单利,但是如果有两个applicationContext呢?

 首先看以下实例 :
  
 首先定义一个bean 并注册为单利,非懒加载对象:
 
package com.joe.service;


public class TestService {

    
public TestService(){
        System.out.println(
"create  TestService ");
    }

}


配置:
<bean id="testservice" class="com.joe.service.TestService" scope="singleton" lazy-init="false"></bean>

测试代码:
    private static ApplicationContext context1;
    
private static ApplicationContext context2;
    
    
static{
        context1 
= new ClassPathXmlApplicationContext(new String[]{"classpath:spring-bean_*.xml"});
        context2 
= new ClassPathXmlApplicationContext(new String[]{"classpath:spring-bean_*.xml"});
        
    }
    
    
public static void main(String[] args) throws SQLException, IOException {
        
        System.out.println(
"context1 中 testservice 是否单利?"+context1.isSingleton("testservice"));
        
        TestService service 
= (TestService) context1.getBean("testservice");
        
        System.out.println(service);
        
        System.out.println(
"context2  中 testservice 是否单利?"+context2.isSingleton("testservice"));
        
        TestService service2 
= (TestService) context2.getBean("testservice");
        
        System.out.println(service2);
        System.out.println(service);
        
        System.out.println(
"context1 中 testservice 是否和context2 中 testservice 是一个对象?"+(service==service2));//关键地方 两个ApplicationContext 中拿 到的是否是一个对象?
    }

结果:
create  TestService 
create  TestService 

context1 中 testservice 是否单利?
true
com.joe.service.TestService@54c4ad
context2  中 testservice 是否单利?
true
com.joe.service.TestService@13c7378
com.joe.service.TestService@54c4ad
context1 中 testservice 是否和context2 中 testservice 是一个对象?
false

 很明显在一个jvm应用中出现两个被标注为单利的实例。
    spring内部通过上下文中的集合来管理对象,核心为beanFactory,而非通过asm等来动态改变类结构来控制类的scope。

     我们跟着源码来看看:
  在调用new ClassPathXmlApplicationContext实际上调用了
  this(configLocations, true, null);其中的true代表要刷新上下文:而最终的refresh是这样的
 
if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }

但是很费解的是hasBeanFactory的判断:
protected final boolean hasBeanFactory() {
        
synchronized (this.beanFactoryMonitor) {
            
return (this.beanFactory != null);
        }

    }

其中的this.beanFactory是ClassPathXmlApplicationContext的实例的属性private DefaultListableBeanFactory beanFactory;
  不用说this.beanFactory==null因为我们new了一个ClassPathXmlApplicationContext , beanFactory也没有初始化操作,也没有parentContext (因为我根本不知道有没有parentContext)而beanFactory也不是static的。
  也就是说在第二次new  ClassPathXmlApplicationContext的时候并不会refresh beanFactory 当然就会有两个单利的实例。
  
    
   

    此问题在项目中出现,当时由于一个同事在自己的一个类里面的static区域new了ClassPathXmlApplicationContext用来测试忘记删掉, 而我们的所有类又是通过web容器来加载,结果就导致项目中出现单利对象出现两个的问题,结果害的那个苦啊!
   
   希望大家在实际项目中注意到,也希望大家跟帖讨论下,我分析的是否正确,大家实际项目中有没有解决方案来避免这样的问题!

评论

# re: 注意spring, singleton不single! ?  回复  更多评论   

2010-08-30 10:01 by 隔叶黄莺
谢谢,又了解到一点知识,范围是基于 applicationContext,而不是 JVM。其实通常的单例,我们要更严格的来讲也不能说是基于 JVM,而是基于 ClassLoader 的。

# re: 注意spring, singleton不single! ?  回复  更多评论   

2010-08-30 10:38 by forest
我测试了一下,发现两个test是相同的。

# re: 注意spring, singleton不single! ?  回复  更多评论   

2010-08-30 10:58 by @joe
@forest
能提供下测试代码看看吗?

# re: 注意spring, singleton不single! ?  回复  更多评论   

2010-08-30 11:11 by Lancelot
人家的singleton本来就是相对于容器的。

# re: 注意spring, singleton不single! ?  回复  更多评论   

2010-08-30 11:43 by @joe
@Lancelot
但是真正的项目中要的是真正的单利,我感觉这种思想脱离了实际应用。给项目带来了麻烦这是事实。我不知道spring是处于何种思想?希望兄台给个解释!

# re: 注意spring, singleton不single! ?  回复  更多评论   

2010-08-30 11:57 by @joe
查看spring的文档然后了解到实质,请看一下文档(来自spring官方文档)
3.4.1. The singleton scope
When a bean is a singleton, only one shared instance of the bean will be managed, and all requests for beans with an id or ids matching that bean definition will result in that one specific bean instance being returned by the Spring container.

To put it another way, when you define a bean definition and it is scoped as a singleton, then the Spring IoC container will create exactly one instance of the object defined by that bean definition. This single instance will be stored in a cache of such singleton beans, and all subsequent requests and references for that named bean will result in the cached object being returned.


请注意一下内容:
**********************************************
Please be aware that Spring's concept of a singleton bean is quite different from the Singleton pattern as defined in the seminal Gang of Four (GoF) patterns book. The GoF Singleton hard codes the scope of an object such that one and only one instance of a particular class will ever be created per ClassLoader. The scope of the Spring singleton is best described as per container and per bean.
*********************************************
This means that if you define one bean for a particular class in a single Spring container, then the Spring container will create one and only one instance of the class defined by that bean definition. The singleton scope is the default scope in Spring

当然spring是per container and per bean.
也就是(Scopes a single bean definition to a single object instance per Spring IoC container.
);
唉 以后注意。

# re: 注意spring, singleton不single! ?  回复  更多评论   

2010-08-30 12:02 by @joe
@@joe
但为什么不使用GoF Singleton 呢??????

# re: 注意spring, singleton不single! ?  回复  更多评论   

2010-08-30 12:29 by anders
@joe
但是真正的项目中要的是真正的单利,我感觉这种思想脱离了实际应用。给项目带来了麻烦这是事实。我不知道spring是出于何种思想?希望兄台给个解释!

...
有点无语。

第一joe没有弄清出spring提供单例范围。spring单例基于container的。
第二joe还没有弄清项目中单例的范围,“什么叫真正的项目真正的单例”,以偏盖全——以自己项目的需求覆盖全部的需求。

对于一个J2EE来说,如果运行在应用服务器下,一个应用服务器可以同时支持多个应用,单例的范围就应该是每个应用一个单例,就是spring的考虑,不能是
两个应用使用同一个单例,会出很多问题比如classload的问题。如果确实需要,则应自己扩展spring的scope,采用jndi的方式获取单例。

“什么叫真正的项目真正的单例”,单例是基于JVM的,还是基于OS的,还是基于内网的,还是基于整个互联网的。

基于JVM的给用静态变量;基于OS的给借助OS特性,比如文件系统;基于内网的和互联网的就根复杂了。。。。

# re: 注意spring, singleton不single! ?  回复  更多评论   

2010-08-30 13:22 by @joe
@anders
首先感谢anders的恢复 !,让人更深入的了解了Singleton !
但是我的情况就是在一个应用中出现了这样的问题,既然一个应用中可以new 多个applicationContext,为什么不加以控制呢!我感觉不应该研发自己去注意这些东西,应该对于一个应用有一个Global Application足以,如果再new application的时候 直接指向前一个applicationContext!这样Singleton 在一个应用中应该可以得到解决!

# re: 注意spring, singleton不single! ?  回复  更多评论   

2010-08-31 11:16 by xylz
@@joe
anders说的很明白了,spring是基于container的!这与单例的作用范围其实没有关系。。。

# re: 注意spring, singleton不single! ?  回复  更多评论   

2010-08-31 13:44 by @joe
@xylz
spring是基于container的.我明白!
但是脱离实际项目谈这些是没有用,给项目带来风险的东西,都是值得考虑,值得注意的,概念谁都懂!

# re: 注意spring, singleton不single! ?  回复  更多评论   

2013-12-21 16:33 by zb
争论有意义吗,说明白不就成了,孔已己似的.

只有注册用户登录后才能发表评论。


网站导航: