Reputation: 15399
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
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
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
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
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
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
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