Using CDI in a singleton pattern

fabpicca picture fabpicca · Feb 28, 2013 · Viewed 23.7k times · Source

I'm trying to inject a logger object in a class that is implemented following a singleton approach.

The code almost looks like this:

Logger class:

public class LoggerFactory {
    @Produces 
    public Logger getLogger(InjectionPoint caller){
        return Logger.getLogger(caller.getMember().getDeclaringClass().getName());
    }
}

Then I create a class that needs logger and implements the Singleton Pattern:

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

}

If I run the code (on Glassfish 3.1.2.2) I get a NPE as soon as I try to use the logger. What I'm doing wrong (beans.xml file is in place)? I've also tried using @Inject with a setter method for the Logger object but with no luck.

Answer

Aksel Willgert picture Aksel Willgert · Feb 28, 2013

Injections happens after construct. So you cant use it in the constructor.

One way is to add a method annotated @PostConstruct that can will be invoked after injections.

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

On a sidenote i Think you are aprouching the problem in the wrong way. CDI has a nice singleton support

create a class annotated @Singleton

@Singleton
public class MySingleton {

    @Inject
    Logger logger;

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

}

Above assumes you are using CDI for java ee (JSR-299).

If you are using JSR 330 Dependency Injection (guice etc.) link

You could use constructor injection:

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