Spring and SPRINGMVC, as the default framework for the Bean Management container and the MVC layer, have been adopted by many Web applications, while in practice, many XML-based configuration methods have been replaced by the powerful annotation functionality, but in actual projects, There are some strange exceptions when configuring spring and SPRINGMVC, such as the bean being loaded multiple times, instantiating multiple times, or relying on injection, the bean cannot be injected automatically, but obviously you have registered the bean. The reason is to look at the root cause of the problem, we start from the container. 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 2 containers, spring is the root container, and SPRINGMVC is its child container. And in the spring root container for the bean in the SPRINGMVC container is not visible, and in the Springmvc container for the bean in the spring root container is seen, that is, the child container can see the registered bean in the parent container, and vice versa. It's important to understand this because it's a rule that spring sets itself, but looking down, we'll find that there are places where it doesn't use this rule by default. When we use annotations, the implementation of the Bean Registration feature does not require the XML to be configured for each bean, as long as the uniform configuration of the following is used.
<context:component-scan base-package= "Com.test"/>
According to the reference manual provided by spring, the function of this configuration is to scan all @component annotations under the default package, and automatically register them in the container, while also scanning @controller, @Service, @Respository the three annotations, They are inherited from @component. In addition to the above we use the scanning configuration, in the project we often see is <context:annotation-config/> this configuration, in fact, with the above configuration, this can be omitted. There is also a SPRINGMVC related to the <mvc:annotation-driven/> Configuration, which is verified, this must be configured, because it is used in conjunction with @requestmapping, This complements the SPRINGMVC framework-related knowledge points.
handlermapping, is the SPRINGMVC used to process the request URL to the specific controller, which itself is divided into many kinds;
Handleradapter, is used in SPRINGMVC to deal with specific requests mapped to specific methods, and its own many kinds of;
@RequestMapping The main purpose of this annotation is to register specific controllers and methods to facilitate handlermapping to handle the mapping of requests. But @requestmapping need to combine <mvc:annotation-driven/> Use to take effect.
Well, with the basics above, let's look at a scenario where spring is in conflict with Springmvc's container. Spring configuration file Applicationcontext.xml,springmvc configuration file Applicationcontext-mvc.xml, so there are 2 containers in the project, configuration mode A, as follows: Applicationcontext.xml is configured in the <context:component-scan base-package= "Com.test"/>, responsible for scanning of all beans that need to be registered, applicationcontext-mvc.xml configuration <MVC:ANNOTATION-DRIVEN&NBSP;/>, responsible for the use of SPRINGMVC related annotations, start the project discovery, SPRINGMVC failure, unable to jump, turn on log debug level for debugging, It is found that the request in the SPRINGMVC container does not appear to be mapped to the specific controller in; configuration B, as follows: To quickly verify the effect, the <context:component-scan base-package= " Com.test "/> Scan configuration to Applicationcontext-mvc.xml, after reboot, verify success, SPRINGMVC jump is valid. To see the specific reasons, look at the source code, from the SPRINGMVC dispatcherservlet start to see, after a request came in, what happened? After a lengthy review, find the reasons below. When &NBSP;SPRINGMVC is initialized, it looks for all the @controller annotations in all current containers to determine if it is a handler, and there is no @controller annotation in the bean registered in the current container springmvc. Note that the configuration described above, a, all @controller-configured beans are registered in the parent container of spring, looking at the code.
Protected void inithandlermethods () { 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); } } Handlermethodsinitiali Zed (Gethandlermethods ()); }
In method Ishandler, the current bean's annotations are determined to be the controller, and the code is as follows:
Protected Boolean Ishandler (Class<?> beantype) {return annotationutils.findannotation (Beantype, CONTROLLER.C LASS)! = NULL; }
In configuration mode B, the SPRINGMVC container contains all the @controller annotations of the bean, so it's natural to find it. The above is the reason, what is the solution? Note that in the Inithandlermethods () method, detecthandlermethodsinancestorcontexts This switch, which mainly controls where the bean from the container is obtained, whether the parent container is included, and is not included by default. So the solution is there, That is, configure Handlermapping's Detecthandlermethodsinancestorcontexts property to True in the SPRINGMVC configuration file (you need to see what kind of handlermapping is used depending on the project) And let it detect the bean of the parent container. As follows:
<bean class= "Org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" > < Property name= "Detecthandlermethodsinancestorcontexts" > <value>true</value> </property > </bean>
There are 2 kinds of solutions, but in the actual project, will include a lot of configuration, according to different business modules to divide, so our general idea is accountability, clear boundaries, spring root container responsible for all other non-controller bean registration, SPRINGMVC is only responsible for registering the bean associated with the controller. The third scenario is as follows:
Spring container configuration, excluding all @controller beans
<context:component-scan base-package= "Com.fsnip.open" > <context:exclude-filter type= "Annotation" Expressi on= "Org.springframework.stereotype.Controller"/> </context:component-scan>
SPRINGMVC The container configuration so that it includes only @controller beans
<context:component-scan base-package= "Com.fsnip.open" use-default-filters= "false" > <context: Include-filter type= "Annotation" expression= "Org.springframework.stereotype.Controller"/> </context: Component-scan>
A third option is recommended for individual comparison. Extension, the project uses the transaction configuration scheme, will also fail in this scenario, in the final analysis is due to the visibility of 2 containers, can be combined with specific problems according to the above ideas to find the reason! (---Full text--) < turn:http://www.open-open.com/lib/view/open1452142677292.html>
Spring container and Spring MVC container