今天看到一个网友骂Spring singletom是个骗子,所以进去仔细看了。
原文如下:
这次被骗代价十分惨重,特此分享以警后人。
简单说说这次经历。事情发生在2006年7月6日。
我们准备设计log系统。采用p6spy,我们订制了一个自己的log输出类。每次logclass生成一个实例,就把他加进一个Set中。在读取sql log的时候,我们使用一个静态方法从一个维护logobject的Set中读出一个logobject,使用这个实例来输出。原则上多线程的操作是要同步的,但是考虑到效率问题,头们决定只是在生成一个logclass实例并向Set中添加时进行同步,而读取时不进行同步。原因就是,我们把 logclass设置成了单态,也就是原则上它只有一个实例。即使多个应用同时启动,也只有固定数量的实例。而这些实例都应该随着web启动而全部预加载。好,大头拍板了,就这么干。
于是,一个恶根被埋下,并在不知不觉地生长。两年来以半年左右一次的频率,一个Exception不断撩拨着我们的神经。客户那边随着 exception的发生也不断有人来问不过开发人员谁也没有在意,毕竟这个例外很友好,它发生在log输出阶段,发生之后会缺失一段log,不过这不算什么影响,大家都以为不用去管,看这个还不如去喝喝茶聊聊天。
今年9月,也就是这个月初。客户突然要求对这个不知所谓的东西严密调查,不然就怀疑我们框架的严密性。好家伙,这些平时温和的客户终于爆发了。好吧,调查。
首先跟踪log.发现在发生这个ConcurrentModificationException发生之前有一次类加载。难道类被重新加载了?如果类被重新加载,基于我对springsingleton的误解,于是我做了一个误判。那就是类被gc掉了。这当然不是没有可能的,如果长时间的闲置,类被回收那么类的静态量就会被重置,那么如果一个线程访问中间静态量被重置的话,那么就极有可能发生异常。我这样判断还有一个原因,springsingleton的类实例只有一个,而我用的都是静态方法,也就是没有引用实例,如果gc,那么这个类的实例很可能被收调,没有实例引用,静态量引用不足以阻止gc。于是接下来我这对我的推断作了一个周的实验,强制gc作了n多遍,无果。我开始对自己的判断产生怀疑,于是仔细察看代码和 log。突然发现几个异常出现都是在web service 开始的一段时间。难道是web service搞得鬼?于是打开web service源代码。一个异常点展现在我面前。每次调用web service,他都会将用到的类重新加载,包括logclass.这样就产生了新的推论。某个线程在访问log class的静态量Set时由于webservice的加载使得set发生变化从而引发异常。试验一下果然如此。
人说千里之堤溃于蚁穴看来不假。如此小的问题竟使得别人对我们的框架产生怀疑,可叹。
总结一下,spring singleton的含义是在一个spring 上下文中保持单态,如果一个jvm上多次加载spring context将使得单态的意义不复存在,与此会产生同步等问题。希望能给大家一些参考。
个人观点:
每次调用web service,他都会将用到的类重新加载,包括log class.
这个是关键。为何每次都会重新加载?
我们看一下Spring的工厂方法。 我们指定了一个application.xml作为配置文件。
如果我们有2个工厂方法呢?他们是2套完全不同的配置,那么所谓的单例还存在吗?
呵呵,不用猜,他们各自使用各自的,不会互相干扰的。
所以。单例一定要在类一级实现,不要指望Spring给你实现。如此,也只能保证一个Context下面的类是单例的。
如果有虚拟主机,虚拟目录,他们的ClassLoader是独立的,同样无法实现单例。
分享到:
相关推荐
9. **最佳实践**:开发过程中可能遵循了一些最佳实践,如代码整洁、模块化设计、使用设计模式(如单例模式、工厂模式等),以及遵循MVC架构原则,使得代码易于维护和扩展。 这个基于Struts-Spring-Hibernate的登录...
在 Java 开发中,常用的设计模式包括工厂模式(Factory Pattern)、单例模式(Singleton Pattern)、观察者模式(Observer Pattern)、装饰器模式(Decorator Pattern)、代理模式(Proxy Pattern)和建造者模式...
2. 单例模式:Spring下默认的bean均为singleton。 3. 代理模式:为其他对象提供一种代理以控制对这个对象的访问。 spring的Proxy模式在aop中有体现,例如JdkDynamicAopProxy和Cglib2AopProxy。 4. 观察者模式:定义...
常见的设计模式包括工厂模式(用于创建对象)、单例模式(确保类只有一个实例)、装饰器模式(动态地给对象添加职责)、观察者模式(定义对象之间的一对多依赖关系,当一个对象状态改变时,所有依赖于它的对象都会...
从提供的文件内容来看,该文档主要围绕Spring Cloud框架和其核心组件在互联网支付领域的应用,以及Java编程语言在处理支付问题时的经验分享。下面我将详细阐述文档中提到的关键知识点。 ### Spring Cloud工作原理 ...
- 讲述一次成功或失败的经验,重点展示从中学到的教训和改进。 8. **个人素质**: - 学习能力和适应性,尤其是在快速变化的IT环境中。 - 对新技术的热情,持续学习和自我提升的态度。 - 问题解决技巧,如何系统...
6. **设计模式**:设计模式是软件设计中常见问题的解决方案模板,如Spring框架中用到了简单工厂(BeanFactory)、单例模式、代理模式(AOP实现)和观察者模式(事件监听)。了解并能灵活运用设计模式是衡量开发者...
2. **设计模式**:在实现系统功能时,可能会用到一些经典的设计模式,例如工厂模式用于创建对象,单例模式用于确保类只有一个实例,观察者模式用于事件驱动,以及MVC(模型-视图-控制器)模式用于分离业务逻辑和用户...
这些词汇构成了开发者日常工作中不可或缺的一部分,无论是初学者还是经验丰富的程序员,了解这些术语都是提高效率和理解能力的基础。 1. **抽象(Abstract)**:在编程中,抽象指的是将复杂的实体简化为更易管理和...
虽然项目描述中未提及,但为了提高代码复用性和可维护性,可以考虑使用设计模式,如单例模式(管理数据库连接)、工厂模式(创建用户对象)等。 9. **测试** 对于一个用户管理系统,单元测试和集成测试是必不可少...
”、“描述一次失败的经历及你如何应对的?”等,提前准备答案,展现你的成熟和反思能力。 "interview-tips-master"这个文件名可能包含了更多具体的面试技巧和策略,如如何准备自我介绍,如何回答技术问题,如何...
动力节点的JAVA基础与进阶课程源代码和笔记集合提供了全面深入的学习材料,旨在帮助初学者及有经验的开发者巩固和提升Java编程技能。这个压缩包包含了一系列的代码示例和学习笔记,覆盖了从基础到高级的Java知识点。...
1. **设计模式**:抽奖程序可能会用到各种设计模式,如工厂模式(用于创建不同类型的奖项)、单例模式(确保抽奖系统只有一个实例)或策略模式(定义不同的抽奖算法)。 2. **数据结构与算法**:抽奖过程中,可能会...
2. **请求处理机制**:SpringMVC采用单例模式管理控制器,每个请求都创建一个新的模型;Struts2采用多例模式,为每个请求创建一个新的Action实例。 3. **性能差异**:SpringMVC在性能上通常优于Struts2,因为它的轻...
- Struts1使用单例模式,因此Action类需要确保线程安全。 - Struts2为每个HTTP请求创建一个新的Action实例,这减少了线程安全问题的复杂度。 3. **Servlet依赖性对比**: - Struts1完全依赖于Servlet API。 - ...
- **设计模式**:工厂模式、单例模式、观察者模式等经典设计模式的应用场景。 #### 3. 常用框架和技术 - **Spring框架**:依赖注入、面向切面编程、事务管理等核心概念。 - **Hibernate框架**:ORM映射、会话管理、...
12. **Spring循环注入的原理**:通过三级缓存机制解决循环依赖问题,即单例对象缓存、完全创建对象缓存和正在创建对象缓存。 13. **Spring AOP术语**:包括切面、连接点、通知、切入点等,这些术语共同构成了Spring ...
- 单例模式。 - 工厂模式。 - 代理模式。 - 观察者模式。 9. **SpringMVC的工作流程** - 接收客户端请求。 - DispatcherServlet 分发请求。 - HandlerMapping 映射请求到 Controller。 - HandlerAdapter ...
3. **软件设计模式**:在尝试构建软件时,理解并应用设计模式(如工厂模式、单例模式、观察者模式等)能帮助我们编写可维护和扩展的代码。 4. **数据结构与算法**:学习和尝试不同的数据结构(如数组、链表、树、图...