我在这里写了这个类
@Component
public class LoginDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public List<Map<String, Object>> getUser(final String username, final String password) {
return jdbcTemplate.queryForList("select * from users where username=? and password=?", new Object[]{username, password});
}
}
现在,它由 JSF 中的托管 bean 使用,它只是在发出请求时创建和使用的 bean(如果使用默认范围)。
@ManagedBean
public class Login implements Serializable {
@ManagedProperty("#{loginDao}")
private LoginDao loginDao;
//..do something with loginDao
}
我担心这完全被破坏了,因为如果当 JSF 创建的 Login bean 去使用那个 LoginDao(它是一个注入(inject)对象)时,并且看到 LoginDao 的字段 jdbcTemplate 为空怎么办?
如果用于处理请求的 Login bean 将在单独的线程中运行(如果 Web 服务器使用该单独的线程来处理该请求),并且由于 LoginDao 的字段 jdbcTemplate 不是最终的并且在构造函数中设置,则可能会发生这种情况运行 Login bean 时,jdbcTemplate 在 Login 实例中不能被视为 null 吗?解决这个问题的方法是使 jdbcTemplate 变得不稳定吗?
而且,现在这让我开始质疑我用 spring 和 JSF 编写的所有内容。使用 @Autowired 注释时是否不可能编写线程安全的类,除非在该字段上使用 volatile 关键字?
我现在真的很担心使用依赖注入(inject)框架。我的意思是,是否可以保证容器注入(inject)的对象不会被视为空引用或处于非最新状态?
最佳答案
Autowiring bean 是在初始化期间注入(inject)的,因此在这种情况下,jdbcTemplate 在处理请求时决不应该为 null。但是,如果您想完全确定,可以通过构造函数注入(inject)它,这是推荐的方法:
@Component
public class LoginDao {
private final JdbcTemplate jdbcTemplate;
@Autowired
public LoginDao(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public List<Map<String, Object>> getUser(final String username, final String password) {
return jdbcTemplate.queryForList("select * from users where username=? and password=?", new Object[]{username, password});
}
}
正如您所说,多个请求很可能由不同的线程处理,并且会发生什么完全取决于定义的范围:
- Spring 中的默认作用域是“singleton”,因此在这种情况下,LoginDAO 在应用程序中将只有一个实例来服务所有请求。在您发布的代码中,这不是问题,因为 JdbcTemplate 是线程安全的。
Also, now this makes me question everything I ever wrote with spring and JSF. Is it impossible to write thread-safe classes when using the @Autowired annotation unless you use the volatile keyword on that field?
完全有可能。这主要取决于您的需要。您可以拥有一个以线程安全方式执行其操作的单例 bean(取决于您的代码和您使用的库),或者您可以让非线程安全 bean 与“请求范围”一起工作(即:一个 bean 实例对于每个请求),或中间的任何内容(spring中有5种范围类型)。
如果出于完全不同的目的,则将字段设置为 volatile 。 volatile 关键字表示字段值将被多个线程不断修改,因此 JVM 不会将其值缓存在线程内以防止竞争条件,并且将以原子方式管理分配。这只会保护字段值,但如果该值是一个对象,则不会保护该对象内部的值。
I am really worried about using a dependency injection framework now. I mean, is there even a guarantee that objects that were injected by the container will not be seen as null for its reference or in a non up to date state?
至少根据我使用 Spring 的经验,我从未遇到过这个问题。 Spring 在初始化和启动时准备一切方面做得非常好,因此您不必担心这一点。但是,建议使用前面指出的构造函数 Autowiring 方法,因为这可以让程序员对您的问题更加安全。
关于java - 我编写的这些类在线程安全方面是否有问题?另外,ManagedBeans 是否在不同的线程中使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48019833/