@Inject和@PostConstruct无法以单例模式工作 [英] @Inject and @PostConstruct not working in singleton pattern
问题描述
我的课程如下:
public class UserAuthenticator {
private static UserAuthenticator authenticator =
@Inject
private UserRepository userRepository;
@PostConstruct
public void init() {
List<User> allUsers = userRepository.findAll();
for (User user : allUsers) {
users.put(user.getEmail(), user.getPassword());
serviceKeys.put(user.getServiceKey(), user.getEmail());
}
}
public static UserAuthenticator getInstance() {
if (authenticator == null) {
authenticator = new UserAuthenticator();
}
return authenticator;
}
}
当我打电话
UserAuthenticator authenticator = UserAuthenticator.getInstance();
init()
方法未调用,userRepository为null
init()
method isn't called and userRepository is null
我的Web应用程序在JBOSS EAP 6.3中运行.
My web application run in JBOSS EAP 6.3.
这是怎么引起的,我该如何解决?
How is this caused and how can I solve it?
推荐答案
在Java EE应用程序中,不要一味思考.那只是麻烦和困惑的秘诀.相反,请考虑"只需创建一个".告诉Java EE容器仅创建整个应用程序范围内指定类的一个实例,并通过Java EE容器提供的功能获取该实例.造成您的具体问题的原因是,您使用new
运算符手动创建了一个类的实例,而没有手动执行注入和构造后调用,就像下面的技术上正确但概念上错误的示例一样:>
In a Java EE application, don't think in singletons. That's only recipe for trouble and confusion. Instead, think in "just create one". Tell the Java EE container to just create only one instance of the specified class, application wide, and obtain the instance via the facility offered by the Java EE container. Your concrete problem is caused because you're manually creating an instance of the class using new
operator without manually performing the injection and post construct call like as the technical correct but conceptually wrong example below:
authenticator = new UserAuthenticator();
authenticator.userRepository = new UserRepository();
authenticator.init();
换句话说,您错误地期望new
运算符可以神奇地识别与Bean管理和依赖项注入相关的注释.
In other words, you incorrectly expected that the new
operator magically recognizes the bean management and dependency injection related annotations.
正确的方法取决于您要指出的一种负责创建和管理指定类的实例的方法.如果是CDI,则只需告诉它使用@Named @ApplicationScoped
创建仅一个应用程序范围的后备bean类的托管bean实例即可.
The right approach depends on the one you'd like to point out as the responsible for creating and managing the instance of the specified class. If it's CDI, then just tell it to create only one managed bean instance of the backing bean class, application wide, using @Named @ApplicationScoped
.
import javax.inject.Named;
import javax.enterprise.context.ApplicationScoped;
@Named
@ApplicationScoped
public class UserAuthenticator {}
它将被创建一次,并可以通过@Inject
在以下任何其他Java EE托管工件中使用(请阅读:在任何其他由@Named
,@Stateless
,@ManagedBean
,@WebServlet
注释的类中, @WebListener
,@WebFilter
,@Path
等).
It will be created just once and be available via @Inject
as below in any other Java EE managed artifact (read: in any other class annotated with @Named
, @Stateless
, @ManagedBean
, @WebServlet
, @WebListener
, @WebFilter
, @Path
, etc..):
@Inject
private UserAuthenticator userAuthenticator;
如果您绝对肯定需要静态方法来获取给定后备类的当前CDI托管Bean实例,那么您应该通过下面的BeanManager
获取它,而不是手动构造该实例(假定Java EE 7/CDI 1.1可用 ):
If you're absolutely positive that you need a static method to grab the current CDI managed bean instance of a given backing class, then you should be obtaining it via BeanManager
as below instead of manually constructing the instance (assuming Java EE 7 / CDI 1.1 available):
@SuppressWarnings("unchecked")
public static <T> T getCurrentInstance(Class<T> beanClass) {
BeanManager beanManager = CDI.current().getBeanManager();
Bean<T> bean = (Bean<T>) beanManager.resolve(beanManager.getBeans(beanClass));
return (T) beanManager.getReference(bean, bean.getBeanClass(), beanManager.createCreationalContext(bean));
}
用法:
UserAuthenticator userAuthenticator = YourCDIUtil.getCurrentInstance(UserAuthenticator.class);
// ...
另请参见:
- Java单例类与JSF应用程序范围内的受管Bean-有区别吗?
- Java EE 6和Singletons
- Java singleton class vs JSF application scoped managed bean - differences?
- Java EE 6 and Singletons
See also:
这篇关于@Inject和@PostConstruct无法以单例模式工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!