我声明了一个Spring bean,它每隔几秒钟轮询我的电子邮件服务器。如果有邮件,它会获取它,并尝试提取其中的任何附件。然后将这些文件提交到Uploader,Uploader安全地存储这些文件。上传器也被声明为Spring bean。第三个bean将电子邮件的发送者与文件的文件名相关联,并将其存储在DB中。
事实证明,当几个人试图同时发送电子邮件时,发生了一堆混乱的事情。数据库中的记录文件名错误。有些根本没有得到文件名,等等。
我将这个问题归因于bean的默认作用域是单例的。这意味着一堆线程可能同时处理一个相同的实例。问题是如何解决这个问题。
如果我同步所有敏感的方法,那么所有的线程都会堆叠在一起并相互等待,这有点违背了多线程的整体思想。
另一方面,将bean的作用域限定为"request“将创建每个bean的新实例,如果我们谈到内存消耗和线程调度,这也不是很好。
我很困惑。我该怎么办?
发布于 2011-09-29 20:50:39
我同意@Bozho和@stivio的答案。
首选的选项是在单个作用域的bean中传递store no state,并将上下文对象传递给方法,或者使用为每个处理周期创建的原型/请求作用域的bean。通过选择这些方法中的一种,通常可以避免同步,并且您可以获得更高的性能,同时避免死锁。只需确保你没有修改任何共享状态,比如静态成员。
每种方法都有优缺点:
在大多数简单的情况下,我倾向于使用服务方法。您还可以让这些单例bean创建一个处理对象,该对象可以保存计算的状态。对于更复杂的场景,这是一种最适合您的解决方案。
编辑:有些情况下,您有一个依赖于prototype作用域bean的单例bean,并且您希望为每个方法调用都有一个新的prototype bean实例。Spring为此提供了几种解决方案:
第一种是使用Method Injection,如Spring参考文档中所述。我真的不喜欢这种方法,因为它迫使你的类变得抽象。
第二种方法是使用ServiceLocatorFactoryBean,或您自己的工厂类(需要注入依赖项并调用构造函数)。这种方法在大多数情况下都工作得很好,并且不会将您与Spring结合在一起。
在某些情况下,您还希望原型bean具有运行时依赖项。我的一个好朋友在这里写了一篇很好的文章:http://techo-ecco.com/blog/spring-prototype-scoped-beans-and-dependency-injection/。
发布于 2011-09-29 20:30:07
单例作用域的bean不应该包含任何状态-这通常就解决了问题。如果您只将数据作为方法参数传递,而不将其分配给字段,那么您将是安全的。
发布于 2011-09-29 20:32:10
否则,只需将bean声明为request,不用担心内存消耗,垃圾回收会将其清除,只要有足够的内存,也不会有性能问题。
https://stackoverflow.com/questions/7597266
复制相似问题