考虑以下Spring Service类。定义的弹簧范围是Singleton。自动连接的两个服务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类是不可变的是正确的,因为它不可能改变它的两个字段中的任何一个(可以通过容器本身只初始化一次的spring bean)吗?
在任何情况下,上面定义的DocumentService bean都可以被认为是线程安全的吗?如果遵循这种设计,整个应用程序也是线程安全的吗?
答案 0 :(得分:20)
说DocumentService类是不可变的是正确的,因为它不可能改变它的两个字段中的任何一个(可以通过容器本身只初始化一次的spring bean)吗? < / p>
根据definition of immutability,正式来说,这个课程不是一成不变的。
如果无法更改对象的状态,则对象是不可变的,documentGenerationService
和documentPublishService
的状态是类的状态的一部分 DocumentService
。
因此,如果该类的总是处于相同状态,则始终的行为方式。换句话说,没有办法改变不可变对象的行为,因为对象的行为只取决于它的状态,而在不可变对象中,这个状态永远不会改变(不可变对象的例子是字符串和整数)。 / p>
请注意,在不变性的定义中,我们发现一个异常,其中“一个对象被认为是不可变的,即使某些属性发生了变化,但对象的状态 [因此,行为] < em>似乎是不变的[...] “,但在这种情况下(提供的信息),引用状态的改变肯定会改变类的行为(因为我们没有对自己内部状态的任何控制。)
有一个 strategy 来使类不可变。你已经遵循了它的一些指导原则,但如果你希望这样做是不可改变的(我认为情况并非如此)你需要其他一些如你所收到的论据的“防御性复制”在构造函数中,避免子类重写方法。
此link也很有趣。
然而,你不应该使Spring bean不可变,因为它不是使用Spring提供的编程模型的方法。因此,在这种情况下,该类不是不可变的“好”。
在任何情况下,上面定义的DocumentService bean都可以被认为是线程安全的吗?
如此处所声明的,此类 IS线程安全。许多线程可以安全地访问此类,而不会出现任何竞争条件。我们不能对它包含的字段说同样的内容,但这个类是线程安全的。这与“线程安全列表”的工作方式相同:它可以包含“无线程安全”对象,但仍然是“线程安全列表”。
如果遵循此设计,整个应用程序也是线程安全的吗?
如果你的系统的所有类都是线程安全的(即不会出现任何一个竞争条件),你可以非正式地说该应用程序是线程安全的。
答案 1 :(得分:4)
Spring不保证线程安全。这是你的责任。
所有私有成员变量都是共享的。它们可能是最终的,但这只意味着引用无法更改。任何可变状态都必须同步。如果它们确实是不可改变的,那么我认为你已经有了坚实的基础。
我同意有关自动装配依赖关系的评论。如果可能的话,我会让那些受Spring控制的人。
答案 2 :(得分:2)
您可以将@Autowired注释放在服务之上,而不是在构造函数中使用它们。它是一个Spring托管bean,这意味着它是一个单例。它是线程安全的,但这取决于实现。
@Service
public class DocumentService {
@Autowired
private DocumentGenerationService documentGenerationService;
@Autowired
private DocumentPublishService documentPublishService;
... methods follow
答案 3 :(得分:2)
您的问题中显示的示例代码绝对是线程安全的。
但是,需要在整个应用程序的上下文中考虑代码。例如,上面的代码不提供有关documentGenerationService
和documentPublishService
属性引用的对象的线程安全性的任何保证。如果它们没有充分同步,那么使用它们的代码(包括此类的其他方法)可能不是线程安全的。
答案 4 :(得分:1)
您的代码看起来是线程安全的。 当它说豆子是单身时,Spring不保证线程安全。如果在spring中创建singleton范围的bean,它只是意味着每个Spring IoC容器创建一个对象实例。但是单例范围的bean类本身可能不是线程安全的,因此程序员有责任使代码线程安全。
在您的代码中,documentGenerationService
例如是最终的。这保证了引用不会改变,并且从新的Java Memory模型中也可以保证实例化。但@duffymo说,被引用的对象也必须是不可变的。
休息一切都很好:)。
答案 5 :(得分:0)