@Inject和@PostConstruct无法以单例模式工作 [英] @Inject and @PostConstruct not working in singleton pattern

查看:722
本文介绍了@Inject和@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

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);
// ...

另请参见:

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆