java - @Inject 和@PostConstruct 不能在单例模式下工作

标签 java jakarta-ee dependency-injection singleton postconstruct

我有一个类如下:

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

我的 Web 应用程序在 JBOSS EAP 6.3 中运行。

这是怎么引起的,我该如何解决?

最佳答案

在 Java EE 应用程序中,不要考虑单例。那只会带来麻烦和困惑。相反,请考虑“just create one”。告诉 Java EE 容器仅在应用程序范围内创建指定类的一个实例,并通过 Java EE 容器提供的工具获取该实例。您的具体问题是因为您手动使用 new 运算符创建类的实例而没有手动执行注入(inject)和后期构造调用,就像技术上正确但概念上错误示例如下:

authenticator = new UserAuthenticator();
authenticator.userRepository = new UserRepository();
authenticator.init();

换句话说,您错误地期望 new 运算符神奇地识别与 bean 管理和依赖注入(inject)相关的注释。

正确的方法取决于您要指出的负责创建和管理指定类实例的方法。如果它是 CDI,则只需告诉它使用 @Named @ApplicationScoped 在应用程序范围内仅创建一个支持 bean 类的托管 bean 实例。

import javax.inject.Named;
import javax.enterprise.context.ApplicationScoped;

@Named
@ApplicationScoped
public class UserAuthenticator {}

它只会被创建一次,并且可以通过 @Inject 在任何其他 Java EE 管理的工件中使用,如下所示(阅读:在任何其他用 @Named 注释的类中, @Stateless, @ManagedBean, @WebServlet, @WebListener, @WebFilter, @Path 等):

@Inject
private UserAuthenticator userAuthenticator;

如果您绝对肯定需要一个静态方法来获取给定支持类的当前 CDI 托管 bean 实例,那么您应该通过 BeanManager 获取它,而不是手动构造实例(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 - @Inject 和@PostConstruct 不能在单例模式下工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31098054/

相关文章:

java - 在Android中将方法从Void更改为Return?

java - 无法获取静态字段的值

java - 如何在 Spring @Service 和非 Spring 对象之间集成?

Java - 类实例化和访问的基础知识

java - 服务器响应设置 boolean 值 true/false

java - 从 JTable 读取输入

java - 需要帮助为 SaaS 聊天设计快速且可扩展的服务器架构

java - 如何从 JavaScript 中访问存储在 session 中的数组变量?

c# - 如何将具体类注册到通用接口(interface)?

java - 是否可以使用从同一个类生成的bean