CodeBlue
CodeBlue

Reputation: 15399

When to use multiple instances of Spring Container?

I am using ApplicationContext as a Spring Container.

However, since I don't want to change my API, I feel the need to use multiple instances of the container as follows -

public static void main(String[] args)
 { 
    ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

    ...
    objA = context.getBean(...);
    objB = context.getBean(...);
 }

// code for Class A

 public void execute() // <-- cannot change this signature 
 {
     ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
     objC = context.getBean(...); // earlier, this was objC = new C();
     objC.method1("...");
 }

So I end up using two different instances of ApplicationContext. When is it appropriate and when is it not appropriate to have multiple instances of ApplicationContext?

Upvotes: 3

Views: 7176

Answers (6)

Raghu
Raghu

Reputation: 1393

There is no need to have mulitple application context. In many cases, we need a shared application context.

In order to avoid creating multiple application context in the application, do the following.

When the applicationcontextprovider bean is created, spring framework will inject the ApplicationContext into the setApplicationContext.

Now we have one static utility method getApplicationContext, which will return the application context whenever required.

whenever you need the application context , you just say:ApplicationContextProvider.getApplicationContext(); , which will return the shared application context.

/* Application Context Provider class */

public class ApplicationContextProvider implements ApplicationContextAware {

    private static Logger logger = Logger.getLogger(ApplicationContextProvider.class);

    private static ApplicationContext ctx;

    @Override
    public void setApplicationContext(ApplicationContext arg0)
            throws BeansException {
        if (arg0 != null) {
            ctx=arg0;
        }
    }

    public synchronized static ApplicationContext getApplicationContext(){
        if (ctx==null) {
            logger.info("Getting the context again as it is null");
            ctx = new ClassPathXmlApplicationContext("Spring-All-Module.xml");
        }
        return ctx;
    }


}

Spring Xml:

<bean id="applicationContextProvider" class="dell.harmony.service.ApplicationContextProvider"></bean> 

From your main program class:

try {
            logger.info("Spring Application Context !!");
            ApplicationContext context = new ClassPathXmlApplicationContext(
                    "/Spring-All-Module.xml");
            logger.info("Spring Application Context - End !!");
        } catch (Exception e) {
                    logger.error("Exception in getting the Spring Application Context !!");
                     /* log the exception */
        }

Whenever you need the context, you simply say: //get application context

ApplicationContext context = ApplicationContextProvider.getApplicationContext();
dl = (SingleDataLoader) context.getBean("singledataloaderdao");

Upvotes: 0

tom
tom

Reputation: 2745

If you have control over the classes, try to implement ApplicationContextAware: http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/context/ApplicationContextAware.html

This will inject the applicationContext into the class giving you the liberty to get any class you need.

As long as class A is initialized by spring this will work. From the code given this is the case.

Upvotes: 1

nook
nook

Reputation: 2396

For my tests, I crated a utilities class and simply used a static instance and created a singleton.

For example:

 public class Utilities {
private static ApplicationContext _applicationContext = null; 
private static void initApplicationContext() {
        if (_applicationContext == null) {
            _applicationContext = 
new ClassPathXmlApplicationContext("PersistenceHelper-context.xml");
        }
    }
}

Then anytime you need it, just say:

Utilities.initApplicationContext();

Upvotes: 1

Brad
Brad

Reputation: 15879

For the majority of applications there should be no need for multiple ApplicationContexts. The main limitation is that you cannot share bean instances across containers. Technically there is no reason why you can't break them up into two containers, but I'm sure there will be some common beans you will want to share like dataSources, and a common business layer, etc.

Looking at your example I'd recommend allowing your class A to accept a SpringApplication context as a constructor (alternatively you could use a setter method)

public class A {

    private ApplicationContext ctx;

    public A(ApplicationContext applicationContext) {   
        ctx = applicationContext;
    }

    public void execute() {
        // do stuff with beans retrieved from "ctx"
    }
}

Your main() will bootstrap; the context and pass it to an instance of A

public class MyMain {

    public static void main(String[] args) {

        A a = new A(SpringContextFactory.getInstance());

        a.execute();        
    }
}

As an extra piece of good design, encapsulate your creation of the context inside a Factory class

public class SpringContextFactory {

    public static ApplicationContext getInstance() {

        String[] contextXml = new String[]{ "resources/spring-context.xml",
                                            "resources/spring-db.xml" };

        return new ClassPathXmlApplicationContext(contextXml);
    }
}

I have found this setup works well with my unit tests

Upvotes: 2

nicholas.hauschild
nicholas.hauschild

Reputation: 42849

In your current code, you are not using Spring correctly. The idea is to wire up your dependencies in Spring and then use one ApplicationContext to load your starting bean (likely from your main() method). It is not ideal to load the same context multiple times in multiple places just to get different beans.

From what I can tell, your code for ClassA should be trying to @Autowired an instance of ClassC (or ObjectC) to its member. You want to do this because ClassA is already a Spring defined bean! Depending on the scope provided to Spring for your ClassC bean, you should either inject the bean directly (for the singleton scope):

@Autowired
private ClassC objC;

Or you should inject a factory for creating instances of the bean (for the prototype scope):

@Autowired
private ClassCFactory objCFactory;

If you make this change, then you have no need to load the ApplicationContext more than once.

Upvotes: 0

Sergii Zagriichuk
Sergii Zagriichuk

Reputation: 5399

Try to use context and just a put application context into YOUR PROGRAM CONTEXT in main method, in other methods you have to just get, in your case use static method from some Context class, it is not a good but you cannot change API

Upvotes: -1

Related Questions