我在这里写了这门课
@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中的managedbean使用,它只是在创建请求时创建并使用的bean(如果使用默认范围)。
@ManagedBean
public class Login implements Serializable {
@ManagedProperty("#{loginDao}")
private LoginDao loginDao;
//..do something with loginDao
}
我很害怕这完全被破坏了,因为如果JSF创建的Login bean使用了loginDao,这是一个注入的对象,并且看到loginDao的字段jdbcTemplate为null?
如果用于处理请求的Login bean将在单独的线程中运行,如果Web服务器使用该单独的线程来处理该请求,并且由于LoginDao的字段jdbcTemplate不是final,并且在运行之前在构造函数中设置,则可能会发生这种情况。登录bean,在Login实例中,jdbcTemplate不能被视为null吗?解决这个问题的方法是使jdbcTemplate变得易变吗?
此外,现在这让我质疑我用spring和JSF编写的所有内容。除非在该字段上使用volatile关键字,否则在使用@Autowired批注时编写线程安全类是不可能的?
我现在真的很担心使用依赖注入框架。我的意思是,是否有保证容器注入的对象不会被视为null引用或非最新状态?
在初始化期间注入自动装配的bean,因此在这种情况下,处理请求时jdbcTemplate永远不应为null。但是,如果你想完全确定,你可以通过构造函数注入它,这是推荐的方法:
@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和JSF编写的所有内容。除非在该字段上使用volatile关键字,否则在使用@Autowired批注时编写线程安全类是不可能的?
它完全有可能。它主要取决于你需要的东西。您可以拥有一个以线程安全的方式执行其操作的单例bean(依赖于您的代码和您使用的库),或者您可以让非线程安全bean使用“请求范围”(即:一个bean实例)对于每个请求),或中间的任何东西(春天有5种范围类型)。
如果出于完全不同的目的,将字段设置为易失性。 volatile关键字表示字段值将被多个线程连续修改,因此JVM不会在线程内缓存其值以防止竞争条件,并将以原子方式管理asignations。这只会保护字段值,但如果值是对象,则不会保护该对象内的值。
我现在真的很担心使用依赖注入框架。我的意思是,是否有保证容器注入的对象不会被视为null引用或非最新状态?
至少在我的春季经历中,我从未遇到过这个问题。 Spring在启动时初始化准备一切都很好,所以你不必担心这一点。但是,建议使用之前指示的构造函数自动装配方法,因为这样可以使程序员更准确地了解您的问题。