views:

3108

answers:

4

As I understand it, Spring MVC application has two distinct contexts, the application context and the web context, which are controlled by applicationContext.xml and dispatcher-servlet.xml, respectively.

Inside my controllers, how do I go about loading a bean into either of these contexts?

Note that I am aware of Getting Spring Application Context. That would answer my question for a stand alone application. Where I would use a factory to load the application context from the xml file, but this seems like the wrong way to go about loading beans in Spring MVC.

+2  A: 

Although a Spring MVC application has two distinct contexts, the web context has access to all the beans loaded in the application context. The application context however cannot access beans in the web context. This is used to enforce separation of concerns, e.g. business rules class does not need to know about the HTTP session. So if you have a bean you need access to from both contexts it will have to be declared within the application context.

Donal Boyle
How does one load the bean once it is in the applicationContext.xml?
James McMahon
I've found that beans loaded in the application can not be accessed in the web context, http://stackoverflow.com/questions/888581/fixing-null-entitymanger-in-spring-mvc-application/889723#889723. Maybe it is a problem with @PersistanceContext annotations.
James McMahon
I actually find it easiest just to use a single context. In web.xml, I declare a org.springframework.web.context.ContextLoaderListener, with the context-param contextConfigLocation pointing to my servlet context file (which in turn imports my xml file for DAO, services, web-mappings, etc, as many as you want). I then configure DispatcherServlet with an init-param "contextAttribute" with value of org.springframework.web.context.WebApplicationContext.ROOT, instead of having DispatcherServlet point to another file. This results in just one applicationContext
matt b
http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/web/servlet/FrameworkServlet.html#setContextAttribute(java.lang.String) and http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/web/context/WebApplicationContext.html#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE.This also cuts down significantly on the number of classes loaded in my JVM.
matt b
I believe it is an issue with @PersistanceContext, because now that I am using a DAO layer, the web context CAN access the application context.
James McMahon
+1  A: 

Any dependencies that your Controller has (such as on service-layer classes, DAOs, etc) should be expressed as normal - through injection, either constructor injection or setter injection.

The context where the controller is mapped just wires it up with any dependencies it needs as normal. The Controller code never needs to work with Spring directly to get any beans, it is wired up with them.

matt b
Agh, I am apparently soft in the head. I wasn't wiring in the bean anywhere and wondering why it wasn't working. Thank you for point out what should have been obvious. I've dealt with Spring before, I've just been looking at stand alone code for so long I forgot to look at the obvious.
James McMahon
+1  A: 

You should use dependency injection and your config files to load beans into your controllers, but if you do need to access the application context directly, any Controller that extends AbstractController (or any of its descendents) has access to the getApplicationContext() method.

Rafe
While ultimately my issue was with bean wiring, thank you for pointing out the getApplicationContext() method. That may come in handy later.
James McMahon
+2  A: 

Matt is absolutely correct. You should not need with any kind of bean-loading/instantiating code in your MVC application, otherwise you're doing something wrong. You define your beans inside the according spring XML configuration files.

<bean id="pinboardServiceTarget" class="com.lifepin.services.PinboardService">
    <property name="pinboardEntryDao" ref="pinboardEntryDAO"/>
</bean>
...
<bean id="pinboardEntryDAO" class="com.lifepin.daos.PinboardEntryDAO">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

Your PinboardService class (this is just from an application I wrote recently) will have a property IPinboardEntryDAO like

public class PinboardService implements IPinboardService{
  private IPinboardEntryDAO pinboardEntryDao;

  ...

  public void setPinboardEntryDAO(IPinboardEntryDAO dao){
     this.pinboardEntryDao = dao;
  }

  public IPinboardEntryDAO getPinboardEntryDAO(){
    ...
  }

  ...
}

public class PinboardEntryDAO implements IPinboardEntryDAO{
   ...
}

Note that inside the the PinboardService class I'm using the DAO interface, not the implementation itself, while in the configuration I'm then injecting the real implementation PinboardEntryDAO. This is a very good practice for separating the different layers (presentation, service and data layer).

Juri
Offtopic, whats with the I prefixed interface names, are you using spring .net or something?
James McMahon
You mean the "I" in front of the interfaces. I'm developing Java and .Net and I personally prefer the prefixed interfaces over the "Impl" suffix on the implementation class. Eclipse also uses this kind of style a lot. In my opinion it is more visible, but it is just a preference.
Juri