Using CDI in a singleton pattern

24,875

Solution 1

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

Solution 2

This will not work, because injection, as already mentioned, will be performed after the constructor is called.

Methods annotated with @PostConstruct are called after injection has been finished and before the object itself will be supplied somewhere else.

However, injection only works if the instance of your class is provided by injection itself. This is due to the injection depending on proxying.

Therefore you will need to inject your MySingleton wherever you need it. To be sure it is a singleton, annotate it @Singleton and the container will work that out for you.

Addiotnally beware, that singleton in terms of CDI spec does not mean only one instantiation, but rather only one initialiation of @PostConstruct.

Share:
24,875

Related videos on Youtube

fabpicca
Author by

fabpicca

Music maniac, mild nerd, lava-lamp owner and almost curious, of everything. Follow me @fabpicca.

Updated on January 15, 2020

Comments

  • fabpicca
    fabpicca over 4 years

    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.

    • Aksel Willgert
      Aksel Willgert about 11 years
      Injections happens after construct. So you cant use it in the constructor
    • JB Nizet
      JB Nizet about 11 years
      Why are you usig a singleton instead of injectin it whre you need it, and let CDI make it a singleton-scoped bean?
    • Perception
      Perception about 11 years
      You should be using @Singleton to indicate to the CDI container that the same instance of a bean should always be injected.
  • fabpicca
    fabpicca about 11 years
    Thanks a lot for the answer @AkselWillgert, I went for the CDI implementation.
  • JN01
    JN01 about 8 years
    Are you talking javax.inject.Singleton or javax.ejb.Singleton here? <gosh they made this confusing>
  • goelakash
    goelakash almost 4 years
    Link is dead @Aksel Willgert