noi.m
noi.m

Reputation: 3132

Using ApplicationContextAware in Singleton class

I am trying to inject an object into a singleton class implementation. Something like this

public class MyObjectWrapper implements ApplicationContextAware {

    public static MyObject myObject;
    private ApplicationContext ctxt;
    private MyObjectWrapper() {}

    public static synchronized MyObject getImpl() {
        if (myObject!=null)
            return myObject;

        MyObjectWrapper myObjectWrapper=new MyObjectWrapper();
        this.myObject = (MyObject) myObjectWrapper.getCtxt().getBean("myobject");
        return myObject;
    }

    @Override
    public void setApplicationContext(ApplicationContext arg0)
            throws BeansException {
        logger.debug("setApplicationContext - " + arg0);
        this.ctxt = arg0;
    }

    public ApplicationContext getCtxt() {
        return ctxt;
    }

    public void setCtxt(ApplicationContext ctxt) {
        this.ctxt = ctxt;
    }

}
  1. It doesnt work, that is when i call MyObjectWrapper.getImpl() i get a null MyObject. i have bean entries for myobject and MyObjectWrapper.

  2. I know using getBean is not the best practice but in this particular example is it acceptable? What is the downside? If not here, i will being doing a similar getBean call in my Main method.

I can do a getBean in my main method (i am accessing the application context there), however i just wanted this Wrapper class to be responsible for creation of this singleton. Objects that need MyObject can just call MyObjectWrapper.getImpl() and they get a singleton object.

Any feedback on the same would be appreciated.

Upvotes: 2

Views: 6565

Answers (1)

nicholas.hauschild
nicholas.hauschild

Reputation: 42849

This won't work because you are instantiating a new instance of MyWrapperObject in your static getInstance() method. Because you are instantiating it, the bean is NOT Spring managed, and therefore the ApplicationContextAware method, setApplicationContext(...), will not be called by Spring.

I am not a fan of this code, but if you want to do something like this, I do have a suggestion. Instead of saving the ApplicationContext to an instance member, save it to a static member. Then, in your static getInstance() method, do not create a new instance of MyWrapperObject, just use the static ApplicationContext that you have to create the instance of MyObject. If this class is indeed a Spring singleton, then you should have nothing to worry about.

Something like this:

public class MyObjectWrapper implements ApplicationContextAware {
    private static MyObject myObject;
    private static ApplicationContext ctxt;
    private MyObjectWrapper() {}

    public static synchronized MyObject getImpl() {
        if (myObject!=null)
            return myObject;

        this.myObject = ctxt.getBean("myobject", MyObject.class);
        return myObject;
    }

    @Override
    public void setApplicationContext(ApplicationContext arg0) throws BeansException {
        ctxt = arg0;
    }
}

Also, don't make your object public. It is a singleton for a reason. You want everyone that calls getInstance() to get the same instance of the object. If you make it public, then anyone can get a hold of it and reassign it if they want. It somewhat defeats the purpose...

Upvotes: 5

Related Questions