@Inject和@PostConstruct不能以单例模式工作

时间:2015-06-28 09:25:00

标签: java java-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

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

这是如何引起的?如何解决?

3 个答案:

答案 0 :(得分:6)

在Java EE应用程序中,不要单身思考。这是麻烦和混乱的唯一方法。相反,请考虑&#34; just create one&#34;。告诉Java EE容器只创建指定类的一个实例,应用程序范围,并通过Java EE容器提供的工具获取实例。您的具体问题是由于您使用new运算符手动创建类的实例而无需手动执行注入和post构造调用,如技术正确但概念上错误的示例下面:

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

换句话说,你错误地认为new运算符会神奇地识别bean管理和依赖注入相关的注释。

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

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

@Named
@ApplicationScoped
public class UserAuthenticator {}

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

@Path

如果您非常肯定您需要一个静态方法来获取给定支持类的当前CDI托管bean实例,那么您应该通过@Inject private UserAuthenticator userAuthenticator; 获取它,如下所示,而不是手动构建实例(assuming Java EE 7 / CDI 1.1 available):

BeanManager

用法:

@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));
}

另见:

答案 1 :(得分:1)

我认为您不应该明确地致电UserAuthenticator.getInstance(),而是将UserAuthenticator定义为@ApplicationScoped,并通过您的应用服务器提供的DI获取实例(@Inject )。 UserAuthenticator should be then initialized properly.

答案 2 :(得分:0)

在对该类执行某些操作之前,不会调用@PostConstruct方法(例如:调用某些方法