I have read:
What is the difference between ApplicationContext and WebApplicationContext in Spring MVC?
@RequestMapping annotation not working if <context:component-scan /> is in application context instead of dispatcher context (more on this one later)
and several others but none of these answers the question:
Why is the scope of <context:component-scan.../>
limited when it is present in the ROOT context of a Spring MVC application?
My understanding is that it causes scanning of all classes in the specified packages and instantiates any beans stereotyped with @Component
or any of its sub-stereotypes (@Repository
, @Service
and @Controller
).
Given:
applicationContext.xml (root context)
<beans...>
...
<context:component-scan base-package="com.myproject"/>
<context:property-placeholder
ignore-resource-not-found="true"
location="classpath:default.properties, file:///etc/gallery/gallery.properties"/>
</beans>
main-servlet.xml (servlet context)
<beans ...>
...
<mvc:annotation-driven/>
<mvc:resources mapping="/image/**" location="file:/${gallery.location}" />
<mvc:resources mapping="/css/**" location="/css/"/>
<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:resources mapping="/images/**" location="/images/"/>
...
</beans>
com/myproject/web/MainController.java
package com.myproject.web;
@Controller
public class MainController
{
...
@RequestMapping("/gallery/**")
public String gallery(ModelMap modelMap, HttpServletRequest req, HttpServletResponse resp) throws IOException
{
...
}
}
The Spring docs state that any beans instantiated in the root context are shared and available to the individual servlet application contexts. Thus the two <context:...>
declarations in the root context should result in beans that are visible in the servlet context. But this does not appear to be the case. I am required to repeat BOTH <context:component-scan.../>
and <context:property-placeholder.../>
in the servlet context.
Omitting the <context:component-scan.../>
in the servlet context results in
Sep 15, 2015 10:08:16 AM org.springframework.web.servlet.PageNotFound noHandlerFound
WARNING: No mapping found for HTTP request with URI [/gallery/habitat/20150813] in DispatcherServlet with name 'main'
Sep 15, 2015 10:08:16 AM org.springframework.web.servlet.PageNotFound noHandlerFound
WARNING: No mapping found for HTTP request with URI [/error] in DispatcherServlet with name 'main'
indicating that the @Controller
was not resolved.
Omitting the <context:property-placeholder.../>
results in a @Value
annotation using a property reference not being processed, which in my case results in some broken links.
Since both these <context:.../>
directives result in bean instantiations, I'm confused as to why the beans are not visible in the child context, in direct contradiction to the documentation. Also, doesn't having two component-scan
statements cause the controller bean to be instantiated twice?
With regards to @RequestMapping annotation not working if <context:component-scan /> is in application context instead of dispatcher context, I do have <mvc:annotation-driven />
in my app context, and the answers here do not explain WHY two component-scan
statements are necessary.
I'm really uncomfortable using "magic" unless I completely understand how it works and can predict how it will behave when I tweak something. So the "solution" of "just add it in both places and move on" is unacceptable.