@Inject and @PostConstruct not working in singleton pattern

你离开我真会死。 提交于 2019-12-23 10:18:13

问题


I have a class as below:

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

When I call

UserAuthenticator authenticator = UserAuthenticator.getInstance();

init() method isn't called and userRepository is null

My web application run in JBOSS EAP 6.3.

How is this caused and how can I solve it?


回答1:


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();

In other words, you incorrectly expected that the new operator magically recognizes the bean management and dependency injection related annotations.

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 {}

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;

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

Usage:

UserAuthenticator userAuthenticator = YourCDIUtil.getCurrentInstance(UserAuthenticator.class);
// ...

See also:

  • Java singleton class vs JSF application scoped managed bean - differences?
  • Java EE 6 and Singletons



回答2:


Well i think you shouldn't explictly call UserAuthenticator.getInstance() but to define the UserAuthenticator for example as @ApplicationScoped and get the instance via DI provided by your app server (@Inject). UserAuthenticator should be then initialized properly.




回答3:


The @PostConstruct method will not be invoked until you do some action on that class (ex: call some methods



来源:https://stackoverflow.com/questions/31098054/inject-and-postconstruct-not-working-in-singleton-pattern

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!