这种设计的弹簧单例豆线安全吗?

考虑下面的春季服务类。定义的弹簧范围是单例。以下类中自动连接为字段的两个服务 Bean 具有相似的结构 - 它们也由以下任一字段组成

  • 春豆本身
  • 无状态类
  • 不可变类

等等。此模式在应用程序设计中总体上使用。

@Service     
public class DocumentService {  
  private final DocumentGenerationService documentGenerationService;
  private final DocumentPublishService documentPublishService;

  @Autowired
  public DocumentService (DocumentGenerationService documentGenerationService,    
                          DocumentPublishService documentPublishService) {
  this.documentGenerationService = documentGenerationService;
  this.documentPublishService = documentPublishService;
}

... methods follow

说 DocumentService 类是不可变的,因为不可能改变它的两个字段中的任何一个(这两个字段是只能由容器本身初始化一次的弹簧豆)是否正确?

无论如何,上面定义的 DocumentService Bean 可以被认为是线程安全的吗?如果遵循这种设计,那么整个应用程序也是线程安全的吗?


答案 1

说 DocumentService 类是不可变的,因为不可能改变它的两个字段中的任何一个(这两个字段是只能由容器本身初始化一次的弹簧豆)是否正确?

根据不可变性的定义,从形式上讲,这个类不是不可变的

如果无法更改对象的状态,并且 和 的状态是类状态的一部分,则对象是不可变的documentGenerationServicedocumentPublishServiceDocumentService

因此,如果类始终具有相同的状态,则它的行为方式始终相同。换句话说,没有办法改变不可变对象的行为,因为对象的行为仅取决于其状态,并且在不可变对象中,此状态永远不会改变(不可变对象的示例是字符串和整数)。

请注意,在不可变性的定义中,我们发现了一个例外,其中“即使某些对象[...]属性会发生变化,但对象的状态[以及,因此,行为]似乎保持不变[...]“,但是在这种情况下(通过提供的信息),引用状态的更改肯定会改变类的行为(因为我们对自己的内部状态没有任何控制)。

有一种策略可以使类不可变。你已经遵循了它的一些准则,但是如果你希望不可变地做到这一点(我认为事实并非如此),你需要一些其他的准则,比如对你在构造函数中收到的参数进行“防御性复制”,并避免子类覆盖方法

这个链接也很有趣。

尽管如此,您不应该使Spring Bean不可变,因为它不是使用Spring提供的编程模型的方法。因此,在这种情况下,类不是不可变的“好事”。

无论如何,上面定义的 DocumentService Bean 可以被认为是线程安全的吗?

如此处所声明的,此类是线程安全的。许多线程可以安全地访问此类,而不会产生任何争用情况。对于它包含的字段,我们不能说同样的话,但是这个类是线程安全的。这与“线程安全列表”的工作方式相同:它可以包含“无线程安全”对象,但仍然是“线程安全列表”。

如果遵循这种设计,那么整个应用程序也是线程安全的吗?

如果系统的所有类都是线程安全的(即任何地方都没有出现单个争用条件),则可以非正式地说该应用程序是线程安全的。


答案 2

弹簧不能保证螺纹安全。这是你的责任。

所有私有成员变量都是共享的。它们可能是最终的,但这仅意味着无法更改引用。必须同步任何可变状态。如果它们确实是不可改变的,那么我认为你已经站稳了脚跟。

我同意关于自动布线依赖项的评论。如果可能的话,我会把这些放在斯普林的控制之下。


推荐