在单例模式中使用CDI

14
我试图向实现单例模式的类中注入日志记录器对象。
代码大致如下:
Logger 类:
public class LoggerFactory {
    @Produces 
    public Logger getLogger(InjectionPoint caller){
        return Logger.getLogger(caller.getMember().getDeclaringClass().getName());
    }
}

然后我创建了一个需要日志记录器并实现单例模式的类:
public class MySingleton{
    @Inject
    private Logger logger;

    private MySingleton instance;

    /*
     * Private constructor for singleton implementation
     */
    private MySingleton(){
        logger.info("Creating one and only one instance here!");
    }

    public MySingleton getInstance(){

        if(instance == null) {
            instance = new MySingleton();
        }

        return instance;
    }

}

如果我运行代码(在Glassfish 3.1.2.2上),一旦尝试使用日志记录器,就会出现NPE。我做错了什么(beans.xml文件已经放置好了)?我还尝试使用@InjectLogger对象的setter方法,但没有成功。

7
构造函数之后才会发生注入,因此您无法在构造函数中使用它。 - Aksel Willgert
1
你为什么要使用单例模式而不是在需要的地方注入它,并让CDI将其变成单例作用域的bean呢? - JB Nizet
1
应该使用 @Singleton 来指示 CDI 容器始终注入相同的 bean 实例。 - Perception
@AkselWillgert - 在我看来,你的答案是正确的。能否重新发布为答案? - kostja
我认为“单例模式”不应该这样做,你应该在getInstance()前面加上“static”。 - meadlai
显示剩余3条评论
2个回答

24
注入发生在构造函数之后,所以你不能在构造函数中使用它。
一种方法是添加一个被 @PostConstruct 注释的方法,该方法将在注入后被调用。
@PostConstruct
public void init() {
    logger.info("Creating one and only one instance here!");
}

在旁边提一句,我认为您的问题解决方式不太对。CDI具有很好的单例支持。
创建一个带有@Singleton注释的类。
@Singleton
public class MySingleton {

    @Inject
    Logger logger;

    @PostConstruct
    public void init() {
        logger.info("Creating one and only one instance here!");
    }

}

假设您正在使用Java EE的CDI(JSR-299)。
如果您正在使用JSR 330依赖注入(guice等)link,您可以使用构造函数注入:
@Singleton
public class MySingleton {


    private final Logger logger;

    @Inject
    public MySingleton (Logger logger) {
        this.logger = logger;
        logger.info("Creating one and only one instance here!");
    }
}

1
非常感谢@AkselWillgert的答复,我选择了CDI实现。 - fabpicca
2
你是在说javax.inject.Singleton还是javax.ejb.Singleton?<天啊,他们把这个搞得很混乱> - JN01
链接已失效 @Aksel Willgert - goelakash

4

这样是行不通的,因为正如之前提到的那样,在构造函数被调用后才会执行注入。

使用@PostConstruct注释的方法在注入完成后被调用,在对象本身被提供到其他地方之前被调用。

然而,仅当类的实例由注入自身提供时,注入才起作用。这是由于注入依赖于代理。

因此,您需要在需要使用MySingleton的任何地方注入它。为了确保它是单例的,请将其标记为@Singleton,容器将为您解决这个问题。

另外要注意的是,根据CDI规范,单例并不仅仅意味着一个实例化,而是仅仅意味着@PostConstruct的一个初始化。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接