I. BACKGROUND
Recently, due to a problem with the package scan of the project, in the process of solving the problem, it was discovered that spring and SPRINGMVC have a parent-child container relationship, and it is because of this that the packet scanning problem often occurs. We are here to analyze and understand the parent-child container relationships of spring and SPRINGMVC and to give the official recommendations for package scanning in spring and SPRINGMVC configuration files.
Ii. conceptual understanding and knowledge paving
In the core concept of the spring overall framework, the container is the core idea, which is used to manage the bean's entire life cycle, and in a project, the container may not have only one, spring can include multiple containers, and the container has the upper and lower layer relationships, One of the most common scenarios is the introduction of the spring and SPRINGMVC frameworks in a project, which is actually two containers, spring is the parent container, and SPRINGMVC is its child container. and the bean registered in the Spring parent container is visible to the SPRINGMVC container, and the bean registered in the SPRINGMVC container is invisible to the spring parent container, that is, the child container can see the registered bean in the parent container, and vice versa.
We can use the unified annotation configuration below to bulk register the beans without having to configure each bean in a separate way with XML.
<base-package= "com.hafiz.www"/>
From the reference manuals provided in spring, we learned that the functionality of this configuration is to scan all classes of @component annotations under the configured Base-package package, and automatically register them in the container, while also scanning @controller, @Service, @ Respository these three annotations, as they are inherited from @component.
In the project we often see the following configuration, in fact, with the above configuration, this can be omitted, because the above configuration will open the following configuration by default. The following configuration declares annotations such as @required, @Autowired, @PostConstruct, @PersistenceContext, @Resource, @PreDestroy, and so on by default.
< Context:annotation-config />
In addition, there is a SPRINGMVC related to the following configuration, verified that this is SPRINGMVC must be configured, because it declares @requestmapping, @RequestBody, @ResponseBody and so on. Also, the configuration defaults to loading a lot of parameter binding methods, such as JSON conversion parser.
</>
The previous version of this configuration spring3.1 and the following configuration methods are equivalent
<!-- Configure the note Controller mapper, which is used in SPRINGMVC to map the request URL to a specific controller - < class= "Org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" /><!-- Configure the Annotation controller mapper, which is used in SPRINGMVC to map specific requests to specific methods- < class = " Org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter "/>
The version after spring3.1 and the following configuration methods are equivalent
<!-- Configure the note Controller mapper, which is used in SPRINGMVC to map the request URL to a specific controller - < class= " Org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping "/>< !-- Configure the note Controller mapper, which is used in SPRINGMVC to map specific requests to specific methods-- <class = "Org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/ >
Third, the specific scene analysis
Let's take a detail of the reason why the spring and SPRINGMVC container conflict is there?
We have a total of two containers for spring and SPRINGMVC, and their profiles are applicationcontext.xml and Applicationcontext-mvc.xml respectively.
1. <context:component-scan base-package= "Com.hafiz.www"/> is configured in Applicationcontext.xml, which is responsible for scanning and registering all the beans that need to be registered.
2. Configure <mvc:annotation-driven/> in Applicationcontext-mvc.xml, responsible for the use of SPRINGMVC related annotations.
3. Start the project we found that SPRINGMVC could not jump, set log print level to debug, and found that the request in the SPRINGMVC container did not appear to be mapped to a specific controller.
4. Configure <context:component-scan base-package= "Com.hafiz.www"/> in Applicationcontext-mvc.xml, reboot, verify success, SPRINGMVC Jump is valid.
Let's look at the specific reasons, look at the source code, starting from Springmvc Dispatcherservlet, we found that SPRINGMVC initialization, we will look for all the SPRINGMVC containers using @controller annotations of the Bean, To determine if it is a handler. 1, 22 step configuration so that the current SPRINGMVC container does not register the bean with the @controller annotation, but all the beans with @controller annotations are registered in the parent container of spring, so SPRINGMVC cannot find the processor , the jump cannot be made. The core source code is as follows:
protected voidInithandlermethods () {if(logger.isdebugenabled ()) {Logger.debug ("Looking for request mappings in application context:" +Getapplicationcontext ()); } string[] Beannames= ( This. detecthandlermethodsinancestorcontexts?beanfactoryutils.beannamesfortypeincludingancestors (Getapplicationcontext (), Object.class): Getapplicationcontext (). Getbeannamesfortype (Object.class)); for(String beanname:beannames) {if(Ishandler (Getapplicationcontext (). GetType (Beanname))) {detecthandlermethods (beanname); }} handlermethodsinitialized (Gethandlermethods ());}
In method Ishandler, the current bean's annotations are determined to be the controller, and the source code is as follows:
protected boolean ishandler (class<?> beantype) { return annotationutils.findannotation ( Beantype, Controller. class NULL ;}
In the 4th step configuration, the SPRINGMVC container also registered all the beans with @controller annotations, so SPRINGMVC can find the processor to handle, thus normal jump.
We find the reason why we can't jump correctly, so what's the solution?
We note that in the Inithandlermethods () method, detecthandlermethodsinancestorcontexts This switch, which mainly controls which containers are fetched and whether the parent container is included, The default is not included. So the solution is to configure Handlermapping's Detecthandlermethodsinancestorcontexts property to True in the SPRINGMVC configuration file (here you need to see what kind of handlermapping to use depending on the project) , let it detect the bean of the parent container. As follows:
class= "Org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" > <property name= "detecthandlermethodsinancestorcontexts" > <value>true</value> </property></bean>
But in the actual project will include a lot of configuration, we follow the official recommendation according to different business modules to separate different containers registered different types of bean:spring parent container responsible for all other non-@controller annotations of the bean registration, The SPRINGMVC is only responsible for registering @controller annotated beans, making them accountability and clear boundaries. Configure as follows
1. Configure in Applicationcontext.xml:
< register non-@controller annotations in the spring container----
<context:component-scan base-package = "Com.hafiz.www" > <context:exclude-filter type= " Annotation "expression=" Org.springframework.stereotype.Controller "/></context:component-scan>
Configuration in 2.applicationcontext-mvc.xml
<!--only beans with @controller annotations are registered in the SPRINGMVC container--
<context:component-scan base-package = "Com.hafiz.www" use-default-filters= "false" > <context:include-filter type= "Annotation" expression= "Org.springframework.stereotype.Controller"/></ Context:component-scan>
See another blog about the role of use-default-filters= "false":
Iii. Summary
Now that we have a clear idea of the parent-child container relationship between spring and SPRINGMVC, and the principle of scanning registration, we can easily assign different types of beans to different containers for management based on official advice. If the bean cannot be found or the SPRINGMVC cannot jump and the configuration of the transaction fails, we can quickly locate and solve the problem. Very happy, there are wood ~
A preliminary glimpse of Spring and SPRINGMVC parent-child container relationship