1. The background

When using Spring MVC, most students will define two configuration files, one is the Spring configuration file Spring. XML, and the other is the Spring MVC configuration file Spring – MVC.

Here’s a question for you. What if you defined a singleton bean with the same ID in both spring. XML and spring-mVC.xml? You can think about it for a second and then you can go on.

I did an experiment and concluded that there would be two beans with the same ID in the container and they would not interfere with each other.

Why is that? Those of you who have studied Spring will certainly question, as we all know that id is the only identifier of a bean, how can there be two beans with the same ID at the same time? Am I talking nonsense?

Forgive me for being a bit of a mystery here, but everyone is right about Spring MVC parent-child containers.

In the process of using Spring MVC, there will be two IOC containers, Spring MVC and Spring, and Spring MVC is a child container of Spring.

So what exactly is this father-child container?

To ensure that I speak with authority, rather than being a peddler of knowledge, I’ll cover both the official Spring documentation and the source code.

2.Spring MVC parent-child container

2.1 web. XML configuration

Again, go to the application portal and look at the web. XML configuration file to find the Spring MVC configuration.

<servlet>
        <servlet-name>spring-mvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
</servlet>
Copy the code

The configuration is simple, just configuring a Servlet of type DispatcherServlet and setting the initialization parameters. What is a DispatcherServlet?

2.2 DispatcherServlet Class Introduction

View THE API documentation

2.3 DispatcherServlet Workflow

  • (1) Send all requests to DispacherServlet first
  • (2) DispacherServlet returns to DispacherServlet.
  • (3) Once the Controller is DispacherServlet, the Controler handles the corresponding business logic.
  • Controler returns the result to DispacherServlet.
  • (5) DispacherServlet parses the result to the view parser to get the corresponding page.
  • (6) DispacherServlet goes to the parsed page.

The DispatcherServlet assumes the role of a central controller to handle requests throughout the process.

2.4 DispatcherServlet Context Inheritance relationship

The image above is from the Spring website:

https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html
Copy the code

The DispatcherServlet has a Servlet WebApplicationContext that inherits from Root WebApplicationContext.

We know from the previous article that WebApplicationContext is actually an IOC container and root WebApplicationContext is a Spring container.

This means that an IOC container has been created in the DispatcherServlet and this container inherits the Spring container, which is a child of Spring.

The official document also includes the following description:

For many applications, having a single WebApplicationContext is simple and suffices. It is also possible to have a context hierarchy where one root WebApplicationContext is shared across multiple DispatcherServlet (or other Servlet) instances, each with its own child WebApplicationContext configuration. See Additional Capabilities of the ApplicationContext for more on the context hierarchy feature.

The root WebApplicationContext typically contains infrastructure beans, such as data repositories and business services that need to be shared across multiple Servlet instances.
Those beans are effectively inherited and can be overridden (that is, re-declared) in the Servlet-specific child WebApplicationContext, which typically contains beans local to the given Servlet.

Copy the code

Combining the picture with the above text, we can get the following information:

  1. An application can contain multiple IOC containers.
  1. The child container of DispatcherServlet is composed of Controller, View Resolvers, and web-related beans.
  1. The parent container root WebApplicationContex contains basic beans, such as DAO and Service beans, that need to be shared among multiple servlets.
  1. If you can’t find a bean in the child container, you can look for the bean in the parent container.

You may understand what I said at the beginning of this article about the parent-child container in Spring MVC, and have your own judgment and answer to that question.

Of course, the article is not finished yet, after all, this is only the understanding of the official document, to further verify, we take out the ultimate weapon:

Read the source code!

2.5 DispatcherServlet source code analysis

This section is divided into two parts: creating the Spring MVC container and obtaining the bean.

2.5.1 Creating a Spring MVC container

The DispatcherServlet is essentially a Servlet. Since it is a Servlet, Those who understand the Servlet life cycle know that the first step of loading Servlet by Web container is to execute the init () function, so the init function of DispatcherServlet is analyzed as a breakthrough point.

@Override public final void init() throws ServletException { // 1. Read parameters such as init parameters, Including setting contextConfigLocation PropertyValues PVS = new ServletConfigPropertyValues (getServletConfig (), this.requiredProperties); //2. Initialize the bean used in servlet initServletBean(); }Copy the code

The function that reads init parameter in step 1 ends up calling setContextConfigLocation () to set the configuration file path. The focus here is on initServletBean (), which continues the trace.

Override protected final void initServletBean() throws ServletException {// Initializes the webApplicationContext this.webApplicationContext = initWebApplicationContext(); }Copy the code
protected WebApplicationContext initWebApplicationContext() {/ / 1. Get rootWebApplicationContext WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContext wac = null; //2. If webApplicatioinContext does not already exist, create webApplicationContextif(wac = = null) {/ / create webApplicationContext wac = createWebApplicationContext (rootContext); }return wac;
}

Copy the code

As you can see above, there are two steps to initializing webApplicationContext.

  • (1) access to the parent container rootWebApplicationContext.
  • (2) Create child containers.

Let’s look at is how to obtain rootWebApplicationContext.

public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
   return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
}

public static WebApplicationContext getWebApplicationContext(ServletContext sc, String attrName) {
   Object attr = sc.getAttribute(attrName);
   return (WebApplicationContext) attr;
}
Copy the code

From the above code I didn’t see it from the ServletContext obtained WebApplicationContext called “WebApplicationContext. ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE”.

Read our students should remember this property is initialized in the Spring container initWebApplicationContext () function of setting up in step 3, the value of that is the Spring IOC container.

Continue looking at creating a webApplicationContext.

protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
   return createWebApplicationContext((ApplicationContext) parent);
}
Copy the code
createWebApplicationContext(ApplicationContext parent) { //1. Get the WebApplicationContext implementation Class, in this case XmlWebApplicationContext Class<? > contextClass = getContextClass(); / / generated XmlWebApplicationContext instance ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); / / 2. Set the rootWebApplicationContext to the parent container wac. SetParent (parent); SetConfigLocation (getContextConfigLocation()); //3. / / 4. Configuration webApplicationContext. ConfigureAndRefreshWebApplicationContext (wac);return wac;
}
Copy the code
Protected void configureAndRefreshWebApplicationContext (ConfigurableWebApplicationContext wac) {/ / bean processing wac.refresh(); }Copy the code

See the students here have been acquainted with the feeling. Yes, this is similar to the logic used in the previous article to create Spring IOC.

The only difference is that in step 2 you set the Spring container to its parent. The process of registering, parsing, and instantiating beans in a new container is handled by the XmlWebApplicationContext class as in the Spring IOC container.

2.5.2 Spring MVC Bean acquisition

In fact, we have introduced the Spring MVC bean in the last article, this time to introduce it separately, deepen memory.

protected <T> T doBeanFactory parentBeanFactory = getParentBeanFactory(); // If the parent container is not empty and this container does not register the bean, go to the parent container to get the beanif(parentBeanFactory ! = null && ! ContainsBeanDefinition (beanName) {// If the parent container has the bean, it calls the method of the parent beanFactory to get the beanreturn(T) parentBeanFactory.getBean(nameToLookup,args); } // If the child container registers the bean, the bean is returned after a series of instantiation bean operations. // The instantiation process..... is omitted herereturn (T) bean;
}
Copy the code

The above code corresponds to the official documentation “if you can’t find a bean in the child container, go to the parent container”.

3. Summary

After reading the above introduction, I believe you are familiar with the concept of Spring MVC parent-child container. Now let’s analyze the question at the beginning of the article.

What if spring.xml and spring-mVC.xml define beans with the same ID? Assuming that id = test.

1. First Spring initialization, an instance of the Test bean is generated in the Spring IOC container.

2.Spring MVC starts initialization and generates an instance of the test bean with an ID.

At this point, each container has a bean with the same ID. Is it confusing to use?

The answer is no.

When you use this bean in your Spring MVC business logic, Spring MVC returns the bean directly from its container.

When you use this bean in Spring business logic, the bean in the child container is returned directly to the bean in the Spring container because the bean in the child container is not visible to the parent.

Although that doesn’t pose a problem. In practice, however, it is recommended that all bean definitions be written in the spring.xml file.

Because singleton beans were originally intended to have only one instance in the IOC container, if both profiles were defined, two identical instances would be created, resulting in a waste of resources and vulnerability in certain scenarios.

End of 4.

Instead of defining beans in XML files, most people now define beans with annotations and then define scan packages in XML files. As follows:

<context:component-scan base-package="xx.xx.xx"/>
Copy the code

What if there are duplicate packages configured in spring. XML and spring-mVC.xml?

If those of you who understand this already know the answer.

The answer is that a large number of identical beans will be generated in both parent-child IOC containers, resulting in a waste of memory resources.

Some of you might have thought that setting the scan package in spring.xml would have prevented this problem.

You can try it out and see what happens. If not, why not?

To find out, stay tuned for the next installment!

To learn more, follow the public account: Medium-ripe pizza