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.
A common mistake with that implementation is to neglect synchronization, which can lead to multiple instances of the singleton class.
The most important drawback of the singleton pattern is sacrificing transparency for convenience. Consider the earlier example. Over time, you lose track of the objects that access the user object and, more importantly, the objects that modify its properties.
Eager initialization: In eager initialization, the instance of Singleton Class is created at the time of class loading, this is the easiest method to create a Singleton class. By making the constructor as private you are not allowing other class to create a new instance of the class you want to create the Singleton.
This annotation is a part of the javax. inject package. It instructs the container to instantiate the singleton once and passes its reference to other objects during the injection.
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!");
}
}
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With