context:component-scan in both applicationContext.xml and dispatcher-servlet.xml - spring

I created a servlet filter which is using some Autowired fields. For making it work I declared it as DelegatingFilterProxy in web.xml . Before this filter, my enitre spring config was in dispatcher-servlet.xml but for some reason declaring bean for this filter was not working in dispacher-servlet. So, I declared it in applicationContext.xml. It started working then but Autwired fields inside filter were then throwing null. To tackle with it I moved
<context:component-scan base-package="com.myproj.abc" />
to applicationContext, filter started working then but url paths defined by my controller classes are no longer mapped. So I need to pull following two lines also in applicationContext
<mvc:default-servlet-handler />
<mvc:annotation-driven />
This solves the issue. But I was wondering is this the right place for all this code? Because Spring security and for static resources and view mapping all these code goes in dispatcher. In one of my other project I faced same issue and there I did like this, declared only following line in applicationContext
<context:component-scan base-package="com.myproj.abc" />
And in dispatcher-servlet I change component scan package to controller only and kept all other code there only(in dispatcher)
<context:component-scan base-package="com.myproj.abc.controller" />
Could anyone please enlighten me on this confusion.

Some terminology: ServletContext is the class. Servlet context is the Spring ApplicationContext for the DispatcherServlet. Application context, also know as root context is the ApplicationContext loaded by the ContextLoaderListener and stored in the web application's ServletContext. It is therefore available to other web application components.
The servlet context is loaded by the DispatcherServlet. The DispatcherServlet retrieves the application context from the ServletContext and uses it as the parent of the servlet context.
A servlet Filter is web application component that has no relation to the DispatcherServlet, ie. it doesn't know about the servlet context.
The javadoc for DelegatingFilterProxy states
Supports a "targetBeanName" filter init-param in web.xml, specifying
the name of the target bean in the Spring application context.
So the Filter bean has to be declared in the application context, not the servlet context.
Put all beans that have application scope in the application context.
Put all beans that have relevance to the MVC stack in the servlet context.
Your component-scan should scan the appropriate packages to support the two rules/suggestions above.
Further reading:
What is the difference between ApplicationContext and WebApplicationContext in Spring MVC?
Web-application context/ root application context and transaction manager setup
Difference between applicationContext.xml and spring-servlet.xml in Spring Framework

Related

DispatcherServlet and ContextLoaderListener in Spring

What is the difference between DispatcherServlet and ContextLoaderListener in Spring framework? Do we need to configure both of them in web.xml when we are using spring framework?
AFAIK each DispatcherServlet will have a WebApplicationContext. By default the DispatcherServlet looks for a spring configuration file named [appname]-servlet.xml under WEB-INF folder.
Do we need to configure DispatcherServlet?
Yes, every spring application should configure DispatcherServlet as it is the one through which all the requests are routed. It decides the appropriate method of the controller class to handle the request. Once controller returns the model along with the logical view, DispatcherServlet takes the help of ViewResolver to resolve the view (generally JSPs) and will pass the model data to the view, which is finally rendered on the browser.
Do we need to configure ContextLoaderListener?
No, this is not mandatory. Spring applications can live with out ContextLoaderListener.
Why do we need ContextLoaderListener?
Usually when we build multi-tier applications we don't want to clutter all the beans in one config file [appname]-servlet.xml. For example if you configure spring security you wanted to include all those beans in security-context.xml, in the same way all the beans belonging to service layer are configured in applicationContext.xml and some would like to configure beans belonging to DAO layer in dao-context.xml. So when you configure all these beans in different context files, you need to let know spring that these files exist as spring only knows about [appname]-servlet.xml. ContextLoaderListener will help spring recognize all the other context files.
Hope this helps!
The root WebApplicationContext is a Spring Application Context shared across the application.
A DispatcherServlet instance actually has its own
WebApplicationContext.
One can have multiple DispatcherServlet instances in an application, and each will have its own WebApplicationContext.
The root WebApplicationContext is shared across
the application, so if you have a root WebApplicationContext and
multiple DispatcherServlets, the DispatcherServlets will share the
root WebApplicationContext.
However, for a simple Spring MVC application, one can even have a situation where there is no need to have a root WebApplicationContext. A DispatcherServlet would still have its own WebApplicationContext, but it doesn’t actually need to have a parent root WebApplicationContext.
So, which beans should go in the root Web Application Context and which beans should go in the DispatcherServlet’s Web Application Context?
Well, general beans such as services and DAOs make their way in root Web Application Context, and more web-specific beans such as controllers are included in DispatcherServlet’s Web Application Context.
When DispatcherServlet starts up, it creates a Spring application context and starts
loading it with beans declared in the configuration files or classes that it’s given.
But in Spring web applications, there’s often another application context. This
other application context is created by ContextLoaderListener
Whereas DispatcherServlet is expected to load beans containing web components
such as controllers, view resolvers, and handler mappings, ContextLoaderListener is
expected to load the other beans in your application. These beans are typically the
middle-tier and data-tier components that drive the back end of the application.
Good luck!

spring mvc applicationcontext.xml and spring servlet.xml difference

In my project, we have a spring mvc application.
It has got both applicationcontext.xml as well as -servlet.xml config files.
Bean definitons are spread in both the files.
I want to know when we have -servlet.xml wats the need for applicationcontext.xml?
Please provide any explanation in this area.
applicationContext.xml will have the bean definitions of the core spring components.
project-servlet.xml will have bean definitions of indivisual servlets.
-servlet.xml can have references to applicationContext.xml not the other way round.
What you refer as applicationContext.xml is the root application context (you put beans there when you need application-wide access to them) and what you refer as the [servlet]-context.xml is a specific Spring Bean configuration xml for Spring MVC's DispatcherServlet.
servlet-context is specific to a servlet and application context is shared for whole application. So when you define a Bean in servlet-context.xml the Bean is available to the context of that specific servlet, but when you define a Bean in application-context.xml it is available in the whole application. So if you have multiple dispatcherServlet you can have separate servlet-context for each servlet. But there is only one application-context for the application

Where to put application level beans in Spring MVC?

Where to put application level beans in Spring MVC? Into root-context.xml or into servlet-context.xml?
Beans declared in root-context.xml (services) are visible for beans in servlet-context.xml (controllers), but not the other way around. Therefore there can be a dependency from controllers to services, but the reverse dependency is forbidden by Spring.
That being said put MVC-independent code (services, DAOs, etc.) in main context and put web-only stuff in servlet context.

Access Dispatcher servlet without accessing Application Context

I'm creating a simple Spring MVC app with a DAO layer. Now I want to access the Spring JdbcTemplate beans that I've initialized in the dispatcher servlet. I've been using FileSystemXmlApplicationContext to get to my dispatcher servlet till now, but I realized its not a good practice for MVC app when I need to deploy it elsewhere.
Can somebody let me know if I can use XmlWebApplicationContext or ClassPathXmlApplicationContext to get hold of the dispatcher servlet config file which resides in the WEB-INF folder?
I don't want to extend any ApplicationAware interface and I've also not got access to servlet context, as I'm using ModelAttribute annotations to get the data from beans in JSPs. Also, I don't have any applicationContext.xml in my web-app.

Inject Spring beans into EJB3

I'm trying to inject Spring beans into an EJB using #Interceptors(SpringBeanAutowiringInterceptor.class) but I cannot get it working with the beanRefContext.xml examples I've seen.
Here's my EJB:
#Stateless
#Interceptors(SpringBeanAutowiringInterceptor.class)
public class AlertNotificationMethodServiceImpl implements
AlertNotificationMethodService {
#Autowired
private SomeBean bean;
}
I've provided a beanRefContext.xml as follows:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="...">
<!-- Have also tried with ClassPathXmlApplicationContext -->
<bean id="context"
class="org.springframework.web.context.support.XmlWebApplicationContext">
<property name="configLocations" value="/config/app-config.xml" />
</bean>
</beans>
But, it seems to be recreating the beans instead of obtaining the existing ApplicationContext. I end up with the following exception because one of my beans is ServletContextAware.
java.lang.IllegalArgumentException: Cannot resolve ServletContextResource
without ServletContext
When using the SpringBeanAutowiringInterceptor, shouldn't it obtain the ApplicationContext instead of create a new one?
I also tried changing my web.xml so the contextConfigLocation points to the beanRefContext.xml, hoping it'd load my Spring config but I end up with the same exception as above.
Does anyone know how to do this properly? The examples I've seen seem to use the same method I'm using which I assume means the beans are being recreated when the Interceptor is invoked (or is that how it's supposed to work and I've misunderstood).
When using the SpringBeanAutowiringInterceptor, shouldn't it obtain the ApplicationContext instead of create a new one?
Yes, and this is in fact what it does. It uses the ContextSingletonBeanFactoryLocator mechanism, which in turn manages a number of ApplicationContext instances as static singletons (yes, even Spring has to resort to static singletons sometimes). These contexts are defined in beanRefContext.xml.
Your confusion seems to stem from the expectation that these contexts have any relation to your webapp's ApplicationContext - they don't, they're entirely separate. So your webapp's ContextLoader is creating and managing a context based on the bean definitions in app-config.xml, and the ContextSingletonBeanFactoryLocator creates another one. They won't communicate unless you tell them to. The EJBs cannot get hold of the webapp's context, since EJBs sit outside of that scope.
What you need to do is to move the beans that need to be used by your EJBs out of app-config.xml and into another bean definition file. This extracted set of bean definitions will form the basis of a new ApplicationContext which will (a) be accessed by the EJBs, and (b) will act as the parent context of your webapp's context.
In order to activate the parent-child link between your webapp's context and the new context, you need to add an additional <context-param> to your web.xml called parentContextKey. The value of this parameter should be the name of the context defined in beanRefContext.xml (i.e. context, in your example).
The beans that stay behind in the webapp's context will be able to reference the beans in the parent context, as will the EJBs. However, the EJBs will not be able to reference anything in the webapp's context.
Also, you cannot use XmlWebApplicationContext in beanRefContext.xml, since that class requires awareness of the webapp, and ContextSingletonBeanFactoryLocator cannot supply that awareness. You should stick with ClassPathXmlApplicationContext there.

Resources