在单例模式中使用 CDI

2022-09-03 18:28:19

我正在尝试在遵循单例方法实现的类中注入记录器对象。

代码几乎看起来像这样:

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。我做错了什么(文件已就位)?我也尝试过使用对象的 setter 方法,但没有运气。beans.xml@InjectLogger


答案 1

注射发生在构造后。因此,您不能在构造函数中使用它。

一种方法是添加一个带注释@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!");
    }

}

上面假设您正在使用CDI进行java ee(JSR-299)。

如果您使用的是 JSR 330 依赖关系注入(guice 等)链接

您可以使用构造函数注入:

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

答案 2

这将不起作用,因为如前所述,注入将在调用构造函数后执行。

注释为 的方法在注入完成后调用,并且在对象本身将在其他地方提供之前调用。@PostConstruct

但是,仅当类的实例由注入本身提供时,注入才有效。这是由于注入取决于代理。

因此,您需要在需要的地方注入MySingleton。要确定它是单例,请对其进行注释,容器将为您解决。@Singleton

另外要注意的是,就CDI规范而言,单例并不意味着只有一个实例化,而只是一个初始化@PostConstruct


推荐