-1

I'm trying to understand the concepts of application context in Spring MVC. To examine it I have created an application with two application contexts Test-application-context1.xml and Test-application-context2.xml and one web application context Test-dispatcher-servlet.xml. In all of these contexts I initialized a simple java bean with two fields:

1) In Test-application-context1.xml:

<bean id="testObject" class="test.TestObject">
    <property name="fName" value="FirstName Context1"/>
    <property name="lName" value="LastName Context1"/>
</bean> 

2) In Test-application-context2.xml:

<bean id="testObject" class="test.TestObject">
    <property name="fName" value="FirstName Context2"/>
    <property name="lName" value="LastName Context2"/>
</bean> 

3) In Test-dispatcher-servlet.xml::

<bean id="testObject" class="test.TestObject">
    <property name="fName" value="FirstName WebContext"/>
    <property name="lName" value="LastName WebContext"/>
</bean> 

I also provided a proper configuration in the web.xml file to initialize all of these contexts when the server starts:

 <servlet>
    <servlet-name>dispatcherTest</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/Test-dispatcher-servlet.xml</param-value>
    </init-param>
    <load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>dispatcherTest</servlet-name>
    <url-pattern>/Test/*</url-pattern>
</servlet-mapping>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/Test-application-context1.xml /WEB-INF/Test-application-context2.xml</param-value>
</context-param>

Now I want to inject these application/web application contexts in one of my controller classes. I'm not sure how to do this for multiple contexts properly. I know when I have one context I can make my class implement ApplicationContextAware so I tried it like this:

@Controller
public class TestController implements ApplicationContextAware{

private ApplicationContext applicationContext;

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    this.applicationContext = applicationContext;
}

@RequestMapping(value = "/Test")
public void Test(HttpServletRequest request) {
    TestObject testObject = applicationContext.getBean("testObject", TestObject.class);
    System.out.println("fName="+testObject.getfName()+"; lName="+testObject.getlName());
    }
}

In the above example I always get values of testObject from Test-dispatcher-servlet.xml so it seems that applicationContext that is being injected here represents web application context, BUT if I let's say rename testObject to testObject1 in 'Test-dispatcher-servlet.xml' and run the same code I will get values from Test-application-context2.xml so here are the questions I have.

1) When we make class implement ApplicationContextAware having multiple contexts which context will be injected to that class? Is it one context that is being injected or does spring somehow combines all of contexts and inject them as one applicationContext object (that would explain why do I get values from a different context when I change the name of the bean in one of the contexts)?

2) What is the proper way to inject multiple application contexts to the class?

I know the above example is not a typical scenario and probably a bad design pattern but I'm just trying to understand how the whole thing works.

Mykhailo Seniutovych
  • 3,527
  • 4
  • 28
  • 50

1 Answers1

2

To answer your 2nd question,

Use @ImportResource as below.

From the docs,

Like @Import, this annotation provides functionality similar to the element in Spring XML. It is typically used when designing @Configuration classes

@Configuration  
@ImportResource( { "Test-application-context1.xml", "Test-application-context2.xml" } )  
public class ConfigClass { } 

This will load all beans from both application contexts into the class ConfigClass.

Update:

So, there will be only one application context exists after this import.

You can access any bean from any imported *.context.xml by using @Autowired

After import, Your example in question will throw NoUniqueBeanDefinitionException, because you have more than 1 bean with the same name (testObject) in same application Context.

Sundararaj Govindasamy
  • 8,180
  • 5
  • 44
  • 77
  • Do you know how can I then refer these imported contexts in the Config class i.e. if I have 3 member variables in Config class `private ApplicationContext applicationContext1`, `private ApplicationContext applicationContext2`, `private ApplicationContext webApplicationContext` and I want to initialize them: `applicationContext1 = "Test-application-context1.xml"`, `applicationContext2="Test-application-context2.xml"` and so on? – Mykhailo Seniutovych Feb 07 '17 at 11:55
  • So as I understood for a web application the way spring works it reads all application/web application xml context configurations and based on these configurations it creates one application context for the whole application from which you can access beans, because of that you cannot have 2 contexts with the sane bean names, am I right? – Mykhailo Seniutovych Feb 08 '17 at 10:31
  • It's a little weird for me because in non web applications you can create 2 application contexts for example `ApplicationContext ctx1 = new FileSystemXmlApplicationContext("WebContent/WEB-INF/Test-application-context1.xml");` and `ApplicationContext ctx2 = new FileSystemXmlApplicationContext("WebContent/WEB-INF/Test-application-context2.xml");` and then you can access them separately `ctx1.getBean("testObject")` and `ctx2.getBean("testObject)"` so I wonder why didn't they implement it this way for web apps i.e. one context per one configuration instead of one context per all configurations – Mykhailo Seniutovych Feb 08 '17 at 10:35