10

I need to get the spring application context from a non bean object. In another thread in SO, the accepted answer suggests to use singleton to get the application context. Getting Spring Application Context

But using singleton makes my code more coupled and less testable, the usual problems discussed in many threads (e.g. What is so bad about Singletons )

The question, is there an elegant way to get the application context from a non bean object without using singleton?

Community
  • 1
  • 1
LiorH
  • 16,760
  • 15
  • 67
  • 91

2 Answers2

8

I think your problem is near about the same I had few days back. I think the following should work for you:

First create a class called AppContextManager like below:

@Component
public class AppContextManager implements ApplicationContextAware{
    private static ApplicationContext _appCtx;

    @Override
    public void setApplicationContext(ApplicationContext ctx){
         _appCtx = ctx;
    }

    public static ApplicationContext getAppContext(){
        return _appCtx;
    } 
}

Annotate the above class with @Component or declare a bean for AppContextManager in your application context xml.

Now in your non-singleton non-spring instance use the following code snippet to obtain any other spring bean:

ApplicationContext ctx = ApplicationContextManager.getAppContext();
SomeSpringBean bean = ctx.getBean(SomeSpringBean.class);

And this would give you the bean instance anywhere in your code.

mickeymoon
  • 4,251
  • 5
  • 29
  • 49
  • 1
    did you create your bean properly for AppContextManager.. either your bean should be in a package under defined by `component scan base package` configuration or declare a bean for the same in your application context xml. – mickeymoon Aug 22 '14 at 06:46
  • @mickeymoon thanks for the answer, Its really help me. – Md. Naushad Alam Mar 02 '16 at 05:25
  • I recognize that this is a very old question but I've seen this solution a few times and I'm not sure how it should work. If in you NON SPRING class you have an object of type ApplicationContext then you must have had a Spring dependency no? Or else you can't call the getBean method. – Nik Aug 22 '17 at 22:24
  • it worked perfectly, thanks! if your structure of derived classes can afford it (or common singletons), you can @Autowire components/beans in this base class – Apex ND Mar 29 '18 at 08:55
8

There's always the bootstrapping problem. For web applications there's usually the outer servlet filter that handles the situation.

If not a web-app, there's no way around some kind of outer singleton or bootstrapper. But; using a singleton here should only affect the testability of that single bootstrapper class. There should really only be very few places in your code that need to reference the container in any explicit manner. So it does not really increase coupling significantly.

Or to rephrase, there should really only be very few non-bean objects that need to access the spring container. If this is not the case, then you're probably not using spring optimally. And most/all of those that need the container should probably just implement BeanFactoryAware or ApplicationContextAware

krosenvold
  • 70,511
  • 27
  • 141
  • 205
  • +1 on this. Singletons should generally be avoided in your application code. For certain kinds of bootstrapping or infrastructure it's not a big deal. Odds are you will not need to unit test your bootstrapper anyways. :) – cliff.meyers Jan 24 '09 at 21:49