• J3
  • Spring (parent container # BUG)

1, the cause of the matter

One day, J3 received a small request to intercept data clues coming into the database. The data entering the database needs to be checked through three channels A, B and C, and the check rules of these three channels are different. As long as one of these channels does not meet the requirements of warehousing, it cannot be stored in the database.

See this, J3 heart is incomparable secretly happy, because it is too simple. Say J3 and write the following code for the requirement:

@RestController
@RequestMapping("/insert")
public class InsertController {

    @Autowired
    private ApplicationContext applicationContext;

    @PostMapping("/")
    public void doInsert(@RequestBody Entity entity){
        // Check the core logic
        Map<String, CheckChain> beansOfType = applicationContext.getBeansOfType(CheckChain.class);
        beansOfType.entrySet().forEach(entry -> {
            if(! entry.getValue().check(entity)){return; }});// Perform the insert to the business class
        // ...}}// Check the interface
public interface CheckChain {
    Boolean check(Entity e1);
}
// A channel check logic
@Component
public class ACheckChain implements CheckChain{
    @Override
    public Boolean check(Entity e1)  {
        // Check logic
        returnBoolean.TRUE; }}// B channel check logic
@Component
public class BCheckChain implements CheckChain{
    @Override
    public Boolean check(Entity e1) {
        // Check logic
        returnBoolean.TRUE; }}// C channel check logic
@Component
public class CCheckChain implements CheckChain{
    @Override
    public Boolean check(Entity e1) {
        // Check logic
        returnBoolean.TRUE; }}Copy the code

The above code is run in the Spring environment. I tested each verification rule separately. After all the rules were tested, I directly used them online.

The catch is that each validation rule is tested individually, without the logic going through the entire process from the Controller to the final data drop. At this point, J3 didn’t know it, but he had written a big Bug that was discovered four months later.

Just a few days ago, the operation side of the company reported that there was a problem with data interception, which was not stopped when it should have been. Then I noticed this problem and immediately went to check the relevant implementation code. After a series of checks, I finally found the clue, see the following code:

Can the Controller get the bean scanned by @Component from the ApplicationContext? In Spring, the answer is no.

So, this is the code that was written by two, and I immediately looked at the code submission record and stood there for a few seconds, but IT was me who wrote the code, and it was four months ago.

After locating the problem, I have a general understanding of the root cause of the problem, so I will fix the online problem first (afraid of delaying the boss’s earnings), and then I will find out the details of the problem.

2. Spring parent container

From the above description, I’m sure many of you have already guessed what the key problem is: the Spring parent-child container.

Then since this, let’s dig a dig its bottom (principle)!

Before I get to the rationale, let me explain what we’re going to do.

  1. Analyze the parent container startup process;
  2. The parent container holds those beans;
  3. Analyze the subcontainer startup process;
  4. The child container holds those beans;
  5. Whether the IOC container injected in Controller is a child or a parent;
  6. Whether the IOC container injected into the Service is a child or a parent;
  7. How to get beans through the IOC container;

2.1. Environment construction

The parent-child container problem, I think it is best to build a Spring and Spring MVC integration shelf out, so as to locate and analyze the principle.

This is my good environment (JDK11), we do not want to build their own can be directly clone a copy of 👉 : address

Start with the basic structure of the project

Web. XML: Configuration file for web project startup, which configures information about Spring and key classes for Spring MVC startup.

Spring-service. XML: parent container configuration file.

Spring-web. XML: subcontainer configuration file.

2.2 Parent container startup analysis

Once the environment is ready, take a look at how the parent container is started.

Web projects are usually packaged and run in Tomcat, which reads the web.xml file in the WebAPP web-INF file in each project, so this is the source of our analysis.

Remember what we configured in the web. XML file when we set up Spring and Spring MVC projects. Yes, it’s a listener: Org. Springframework. Web. Context. ContextLoaderListener, It implements the ServletContextListener interface and ServletContextListener is part of the Servlet API, and when the Servlet container starts or terminates a Web application, The ServletContextEvent event is emitted, which is handled by the ServletContextListener. Two methods for handling ServletContextEvent events are defined in the ServletContextListener interface:

  • ContextInitialized (ServletContextEvent sCE) : This method is called when the Servlet container starts the Web application.
  • ContextDestroyed (ServletContextEvent SCE) : Called when the Servlet container terminates the Web application.

ContextInitialized (contextInitialized); contextInitialized (contextInitialized); contextInitialized (contextInitialized); contextInitialized (contextInitialized);

org.springframework.web.context.ContextLoaderListener # contextInitialized

@Override
public void contextInitialized(ServletContextEvent event) {
   // The parent container starts the entry
   initWebApplicationContext(event.getServletContext());
}
Copy the code

From the name of the method, we know that is an entry to initialize the Web context application, which does two main things:

  1. Create the parent container
  2. Initialize the created parent container

Enter the initWebApplicationContext method

org.springframework.web.context.ContextLoader # initWebApplicationContext

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {

    // ...

    if (this.context == null) {
        // create parent container
        this.context = createWebApplicationContext(servletContext);
    }
    if (this.context instanceof ConfigurableWebApplicationContext) {
        ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
        if(! cwac.isActive()) {if (cwac.getParent() == null) {
                // Set the parent to null, meaning that the Spring parent has no parent
                ApplicationContext parent = loadParentContext(servletContext);
                cwac.setParent(parent);
            }
            // initialize the parent containerconfigureAndRefreshWebApplicationContext(cwac, servletContext); }}// ...

}
Copy the code

There is no need to create a parent container, just create a container object by reflection. Key points in the second part, the initialization of the parent container configureAndRefreshWebApplicationContext contains the contents of this method is very much, this I also again only analyze its beans related part of the life cycle, This is the life cycle of the two beans MyTestController and MyTestService in this project.

Enter the configureAndRefreshWebApplicationContext method

org.springframework.web.context.ContextLoader # configureAndRefreshWebApplicationContext

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
    // ...

    // Refresh the core method of the entire container
    wac.refresh();
}
Copy the code

Anyone familiar with the Spring framework is familiar with the Refresh method, which is arguably the main method for the entire Spring startup process.

Enter refresh method

org.springframework.context.support.AbstractApplicationContext # refresh

public void refresh(a) throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {

        // ...
        
        // Create beanFactory to read the spring-service.xml configuration file
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // ...
        
        // Create and initialize all scanned single-instance beansfinishBeanFactoryInitialization(beanFactory); }}Copy the code

Considering the length and the content involved in this case, I will only analyze these two methods.

1. ObtainFreshBeanFactory () method analysis

This method basically does two things:

  1. Create the Bean factory
  2. Read the configuration file, find out the Bean information to be created and save it to the corresponding location

These two things are represented by the refreshBeanFactory() method, so let’s go inside:

org.springframework.context.support.AbstractRefreshableApplicationContext # refreshBeanFactory

protected final void refreshBeanFactory(a) throws BeansException {
    // Destroy the factory if it exists
    if (hasBeanFactory()) {
        destroyBeans();
        closeBeanFactory();
    }
    try {
        // create a Bean factory
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        beanFactory.setSerializationId(getId());
        customizeBeanFactory(beanFactory);
        // Add BeanDefinitions to beanFactory. // Add BeanDefinitions to beanFactory
        loadBeanDefinitions(beanFactory);
        synchronized (this.beanFactoryMonitor) {
            this.beanFactory = beanFactory; }}catch (IOException ex) {
        throw new ApplicationContextException("I/O error parsing bean definition source for "+ getDisplayName(), ex); }}Copy the code

The first point of creating or nothing analysis, he just created a DefaultListableBeanFactory the beanFactory type.

The second point is the focus of this analysis. It loads the Spring configuration file, reads the scan rules defined in the configuration file, and encapsulates the Bean definitions that meet the rules into BeanDefinitions one by one and stores them in the created Bean factory.

Go ahead and see the loadBeanDefinitions(beanFactory) method!

org.springframework.web.context.support.XmlWebApplicationContext # loadBeanDefinitions

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
   // Create a reader for XML
   XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

   // ...
    
   // Initialize the reader
   initBeanDefinitionReader(beanDefinitionReader);
   // Load BeanDefinitions using the XML reader according to the configuration file
   loadBeanDefinitions(beanDefinitionReader);
}
Copy the code

I’m not going to talk much about the creation of the reader, but if I move on, Program will eventually by creating Xml reader eventually went down to the doLoadBeanDefinitions (inputSource, encodedResource getResource () method to the real loading the configuration file.

Look at the doLoadBeanDefinitions method.

org.springframework.beans.factory.xml.XmlBeanDefinitionReader # doLoadBeanDefinitions

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
    throws BeanDefinitionStoreException {
    // ...
    // Wrap the Spring configuration file as a Document object
    Document doc = doLoadDocument(inputSource, resource);
    // Define BeanDefinitions as a Document object
    return registerBeanDefinitions(doc, resource);
    // ...
}
Copy the code

The first point of parsing XML files to generate the corresponding Document object implementation is a bit complicated, SO I will briefly summarize it with my understanding. All tag elements configured in spring-service.xml are parsed in this section as an attribute of the Document object.

The BeanDefinitions method reads the attributes of the Document object to registerBeanDefinitions.

So with this approach, we’re going to focus on the second part, because the first part you can think of as turning our spring-service.xml configuration file into something that Spring can read, the configuration information hasn’t actually taken effect yet, RegisterBeanDefinitions (doc, Resource) is what is starting to take effect for our configuration.

Visit the registerBeanDefinitions(DOC, Resource) method

org.springframework.beans.factory.xml.XmlBeanDefinitionReader # registerBeanDefinitions

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
   // Create a reader that reads Document
   BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
   int countBefore = getRegistry().getBeanDefinitionCount();
   // Start reading
   documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
   return getRegistry().getBeanDefinitionCount() - countBefore;
}
Copy the code

Here’s another reader that creates something, which is a no-guesswork to parse or read a Document object. Here would be to parse through BeanDefinitionDocumentReader BeanDefinition related Document object registration.

DocumentReader. RegisterBeanDefinitions will appoint a representative method, special processing parsing from the Document object nodes, according to the different node call different analytical methods.

RegisterBeanDefinitions has a number of method calls. I’ll list the steps, but I won’t post the code, because it’s not the focus of my analysis and it’s too long to list all of them, so I’ll skip them here.

  1. org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader # registerBeanDefinitions
  2. org.springframework.beans.factory.xml.BeanDefinitionParserDelegate # parseCustomElement
  3. org.springframework.context.annotation.ComponentScanBeanDefinitionParser # parse
  4. org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan

The doScan method is the end we have followed step by step. Its main function is to encapsulate our defined Bean as BeanDefinitionHolder and return it to the Bean factory.

// basePackages we configure packages to scan cn.j3.myspring
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    // Define BeanDefinitionHolder
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    // Iterate over the path to scan
    for (String basePackage : basePackages) {
        // Get all classes in this path that match the @Components annotation of the XXXFilters rule
        Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
        // Iterate over the scanned BeanDefinition
        for (BeanDefinition candidate : candidates) {
            // Generate the Bean's name and return it with BeanDefinitionHolder
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
            / / generated beanName
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
            if (candidate instanceof AbstractBeanDefinition) {
                postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
            }
            if (candidate instanceof AnnotatedBeanDefinition) {
                AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
            }
            if (checkCandidate(beanName, candidate)) {
                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                definitionHolder =
                    AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                // Store it in the set set
                beanDefinitions.add(definitionHolder);
                // Register with beanFactory
                registerBeanDefinition(definitionHolder, this.registry); }}}/ / return
    return beanDefinitions;
}
Copy the code

The main function of this class is to scan the package path defined by the configuration file and find out and encapsulate beans that meet the definition to form BefinitionHolder and register it in beanFactory.

At this point, our beans are registered with the BeanFactory, and the instantiation will have to wait until later. Instantiation is not a big step. The MyTestController Bean is not found in the MyTestController Bean.

<! Set the package for scanning components -->
<context:component-scan base-package="cn.j3.myspring">
    <! Tell Spring not to scan Controller annotated packages -->
    <context:exclude-filter type="annotation"
                            expression="org.springframework.stereotype.Controller"/>
    <context:exclude-filter type="annotation"
                            expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
Copy the code

Take a look at our configuration file (spring-service.xml). It already defines the class that Spring tells it not to scan the @Controller annotation, and this is the code: IsCandidateComponent (metadataReader) in the findCandidateComponents(basePackage) method determines.

At this point, we have the Bean definition information stored in the BeanFactory. Now we just need to instantiate these beans. That the feature is that it (finishBeanFactoryInitialization (the beanFactory)) it’s time to work.

2, finishBeanFactoryInitialization analysis (the beanFactory) method

The main function of this method is to instantiate all non-lazy-loaded beans registered in the beanFactory. The core code is as follows:

org.springframework.context.support.AbstractApplicationContext # finishBeanFactoryInitialization

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // ...
    
    // Instantiate all non-lazy-loaded beans
    beanFactory.preInstantiateSingletons();
}
Copy the code

Since the bean information is stored in the beanFactory, it should be instantiated by calling the beanFactory as follows:

org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons

public void preInstantiateSingletons(a) throws BeansException {

    // ...

    // Get all defined beannames
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

    // Loop instantiation
    for (String beanName : beanNames) {
        // ...

        // A series of Bean lifecycle processes
        getBean(beanName);
        
        // ...

    }

    // The loop triggers post-initialization callbacks for all beans
}
Copy the code

Because we know what beans are supposed to be in the parent container, Bean instantiation is not our focus, but one thing we do know.

Remember that we injected an ApplicationContext object into MyTestService. Spring will eventually inject the IOC container when instantiating MyTestService!

This right here, you don’t even think about it, it’s a hundred percent sure, is the parent container. Since the spring-MVC child hasn’t started yet, the IOC container injected by the Bean in the parent container must be the parent container.

Drawing master to the parent container start process to do the execution flow chart, as follows:

2.3. Startup analysis of sub-containers

For child container startup, we also look at the web.xml configuration file.

In, the SpringMVC framework we only on the web. The XML configuration file is configured with org. Springframework. Web. Servlet. The DispatcherServlet, so our entry is that it.

Let’s start with the class inheritance structure:

As you can see from the above figure, the DispatcherServlet indirectly inherits the Servlet so it is a Servlet that executes the Servlet lifecycle methods when the Web container is started.

The DispatcherServlet is no exception, so our child container start analysis is the Init () method of the DispatcherServlet class.

Let’s go to the init() method and see:

org.springframework.web.servlet.HttpServletBean # init

public final void init(a) throws ServletException {

    // ...

    // Let subclasses do whatever initialization they like.
    // Subclass implementation of HttpServletBean initializes the servletBean
    initServletBean();

    // ...
}
Copy the code

The init method doesn’t do anything real, but it does reserve an initServletBean method for its subclasses to extend, and that’s what we want, so let’s play around.

org.springframework.web.servlet.FrameworkServlet # initServletBean

protected final void initServletBean(a) throws ServletException {
    
    // ...
    // Start the entry of the child container
    this.webApplicationContext = initWebApplicationContext();
    // The method is reserved without any logic
    initFrameworkServlet();
    
    // ...

}
Copy the code

Finally saw the we want initWebApplicationContext, it is the entrance, children start point.

org.springframework.web.servlet.FrameworkServlet # initWebApplicationContext

protected WebApplicationContext initWebApplicationContext(a) {
    // Get the parent container, which we analyzed above
    WebApplicationContext rootContext =
        WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    WebApplicationContext wac = null;

    / / the first initialization, enclosing webApplicationContext must be null
    if (this.webApplicationContext ! =null) {
        wac = this.webApplicationContext;
        if (wac instanceof ConfigurableWebApplicationContext) {
            ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
            if(! cwac.isActive()) {if (cwac.getParent() == null) {
                    // Set the parent container for the child container
                    cwac.setParent(rootContext);
                }
                // Same as the parent container initializationconfigureAndRefreshWebApplicationContext(cwac); }}}if (wac == null) {
        // WebApplicationContext cannot be found because it has not been created
        wac = findWebApplicationContext();
    }
    if (wac == null) {
        // The first time you execute it, you will definitely go here and create the child container !!!!!!! (Emphasis) !!!!
        wac = createWebApplicationContext(rootContext);
    }

    if (!this.refreshEventReceived) {
        onRefresh(wac);
    }

    if (this.publishContext) {
        String attrName = getServletContextAttributeName();
        getServletContext().setAttribute(attrName, wac);
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
                              "' as ServletContext attribute with name [" + attrName + "]"); }}return wac;
}
Copy the code

Initializing the subcontainer method has two main logics, the first is that the subcontainer was created, and the second is that the subcontainer was not created.

  1. Child container is created, access to the parent container it is set as the children of the parent container, and perform the initialization logic as the parent container, namely configureAndRefreshWebApplicationContext method.
  2. Children did not create, try to find time, such as has not been found, in the creation, go createWebApplicationContext (rootContext) method.

Obviously we this time, is the second kind of logic, enter createWebApplicationContext method.

org.springframework.web.servlet.FrameworkServlet # createWebApplicationContext()

protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
    // ...

    // Create the child container first
    ConfigurableWebApplicationContext wac =
        (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

    // Set the environment for the child container
    wac.setEnvironment(getEnvironment());
    // Set the parent container for the child container
    wac.setParent(parent);
    // Get the spring-web. XML configuration file
    String configLocation = getContextConfigLocation();
    if(configLocation ! =null) {
        // This is the child container configuration file
        wac.setConfigLocation(configLocation);
    }
    // Start initializing the child container
    configureAndRefreshWebApplicationContext(wac);

    // return the initialized child container
    return wac;
}
Copy the code

You can see that this method is again the usual two big steps, create and initialize.

There is a difference between the Parent container and the child container. The child container sets the Parent property of the newly created child container.

This is of course for automatic assembly, we often write the Controller is not to assemble various Sertvice beans, and these beans, of course, are from the parent container. Although we could have done it from a child container, that is, in spring-web.xml, we generally don’t do this.

Finally, after we initialize our child container, let’s guess if the ApplicatuionContext injected into MyTestController in our project is a child or a parent. It’s a child.

Drawing master to the child container startup process to do the execution flow chart, as follows:

3, discuss applicationContext. GetBeansOfType (Class)

On it we have to strip the spring container bottom pants, father and son that we can now to the bare spring analysis to analyze why the Controller using pplicationContext. GetBeansOfType method will get less than problems.

So in MyTestController you go to the getBeansOfType method first.

org.springframework.beans.factory.support.DefaultListableBeanFactory#getBeansOfType

public <T> Map<String, T> getBeansOfType(@Nullable Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)
    throws BeansException {
    // Get the bean name according to type
    String[] beanNames = getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
    Map<String, T> result = new LinkedHashMap<>(beanNames.length);
    // If beanNames is empty, there is no process below
    for (String beanName : beanNames) {
        // Get the bean according to beanName
    }
    return result;
}
Copy the code

As you can see, the focus of this method is on getBeanNamesForType. If the method does not get the beanName, there is no further step to get the Bean by name. So let’s look at the implementation logic of getBeanNamesForType.

org.springframework.beans.factory.support.DefaultListableBeanFactory # getBeanNamesForType

public String[] getBeanNamesForType(@NullableClass<? > type,boolean includeNonSingletons, boolean allowEagerInit) {
    // I'm not sure what that means
    if(! isConfigurationFrozen() || type ==null| |! allowEagerInit) {return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
    }
    // The following steps are important, the top step will not be taken
    // Get it from the cache. The first time you get it, it must be emptyMap<Class<? >, String[]> cache = (includeNonSingletons ?this.allBeanNamesByType : this.singletonBeanNamesByType);
    String[] resolvedBeanNames = cache.get(type);
    if(resolvedBeanNames ! =null) {
        return resolvedBeanNames;
    }
    // Get the bean by type. The first time you get the bean, you must go here
    resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
    if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
        // Get a bean of the same type from the cache next time
        cache.put(type, resolvedBeanNames);
    }
    // Return the result
    return resolvedBeanNames;
}
Copy the code

The main thing about this method is doGetBeanNamesForType. Click on it.

org.springframework.beans.factory.support.DefaultListableBeanFactory # doGetBeanNamesForType

private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
    List<String> result = new ArrayList<>();

    // Loop over all beans in the BeanFactory, check if the type is passed in, store it in the list and return it
    for (String beanName : this.beanDefinitionNames) {
        // You can skip the analysis}}Copy the code

See note do not know everybody again did not suddenly realize, here want to take an examination of everybody talent cough up!

Notice the for loop, which only loops through the this.beanDefinitionNames collection, meaning that the getBeansOfType method will only look for matching beans in this container based on the Class type.

Let’s recall that when the parent container is started, each container has those beans. MyTestService in our project is defined in the parent container, so it will be stored in the parent container. And MyTestController is defined in a child container, so it’s going to be stored in a child container.

Since the ApplicationContext injected into MyTestController is a child container, you can’t find the Bean in the parent container by using getBeansOfType.

Of course, if you go to MyTestService and get MyTestController based on getBeansOfType, you can’t get MyTestController either, same thing.

If you think about it more, you suddenly see the light on the Spring parent-child container problem.

4, discuss applicationContext. GetBean (Class)

So let’s move on to the genBean method, because in MyTestController we get the bean from the parent container through the child container.

Enter the getBean code.

@Override
public <T> T getBean(Class<T> requiredType, @Nullable Object... args) throws BeansException {
    // By type, in this container
    NamedBeanHolder<T> namedBean = resolveNamedBean(requiredType, args);
    if(namedBean ! =null) {
        // There is one in this container
        return namedBean.getBeanInstance();
    }
    // This container does not exist
    BeanFactory parent = getParentBeanFactory();
    if(parent ! =null) {
        // Find the parent container
        return(args ! =null ? parent.getBean(requiredType, args) : parent.getBean(requiredType));
    }
    // Not found
    throw new NoSuchBeanDefinitionException(requiredType);
}
Copy the code

The code is very simple. First look for the bean of type type in the container. If you can’t find it, look for the parent of the container.

This makes sense because we use the child container in MyTestController to get the Bean from the parent container via getBean.

MyTestController = MyTestController; MyTestController = MyTestController; MyTestController = MyTestController; MyTestController = MyTestController

The answer is, no.

As for why can not find, you can carefully think about it, well, the length of this article is also a little long, the first analysis to this.

If you don’t understand my final answer, please leave a comment in the comment section or contact me directly. I am happy to discuss with you.

When the end of this story, I know that the three-day holiday will be gone, at this time my mood is like this…

Well, that's it for today, so follow me and we'll see you next time

If you have any questions, please contact me at:

QQ: 1491989462

WeChat: 13207920596


  • Due to the lack of knowledge of the blogger, there will be mistakes, if you find mistakes or bias, please comment to me, I will correct it.
  • If you think the article is good, your retweets, shares, likes and comments are the biggest encouragement to me.
  • Thank you for reading. Welcome and thank you for your attention.