使用 Spring 的线程安全、无状态设计

Posted

技术标签:

【中文标题】使用 Spring 的线程安全、无状态设计【英文标题】:thread safe, stateless design using Spring 【发布时间】:2012-06-26 17:48:54 【问题描述】:

我假设如果实例变量由 Spring IOC 管理,并且是单例,那么设计可以称为无状态和线程安全。因此,这种类型的设计可以扩展到集群服务器。我的假设是否正确,如下所述?

@Repository("myDao")
public class MyDao implements Dao 

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Value("$sqlFoo")
    private String foo;

    @Override
    public Integer getMyInt(String str) 
      return jdbcTemplate.queryForInt(foo, str);
    

然后注入:

@Service("myService")
public class MyServiceImpl 

    @Resource(name = "myDao")
    Dao dao;

    @Override
    @Transactional(readOnly = true)
    public int getScore(String str) 
      return dao.getMyInt(str);
    

【问题讨论】:

【参考方案1】:

Spring bean 不是无状态的,因为它们有状态(字段)。从技术上讲,它们甚至不是不可变的,因为您可以随时更改注入的字段。

但是,您可以通过使用 final 字段和构造函数注入轻松地使 Spring bean 不可变。从可扩展性的角度来看,这种状态也没有问题。如果您的 bean 包含随时间变化的可变值,则这是集群时的主要问题。但在 Spring 服务中,通常只包含在引导时注入的依赖项。因此它们实际上是无状态且不可变的。

运行同一个 Spring 应用程序的服务器数量无关紧要 - bean 和依赖项本身是安全的。 但是如果你的 Spring bean 包含计数器、缓存、可变映射等 - 你需要考虑它们。

【讨论】:

再次感谢,为了使它们成为纯无状态的,我可以使用 dao 等的方法本地实例,但这会因此速度慢得多并且资源繁重,因为将为每个请求创建一个新对象/线程,因此不建议,因为我知道他们不会改变? @NimChimpsky:在这种情况下使用局部变量没有意义(以及如何从上下文中获取它们)? 我误以为它们会在运行时被注入,但你不能在方法中进行注释。 这是否意味着在设计一个用于处理表单提交的控制器时,您应该担心Controller和使用Autowired注解注入的Service?

以上是关于使用 Spring 的线程安全、无状态设计的主要内容,如果未能解决你的问题,请参考以下文章

Spring框架中的单例bean是线程安全的吗?

聊一聊Spring在单例模式下的线程安全

java并发安全详解

java并发编程:管程内存模型无锁并发线程池AQS原理与锁线程安全集合类并发设计模式

java并发编程:管程内存模型无锁并发线程池AQS原理与锁线程安全集合类并发设计模式

在JAVA中ArrayList如何保证线程安全