BeanFactory & FactoryBean

What about BeanFactory and FactoryBean? Not only do they look alike, they pair off with each other during interview questions. However, in fact, the relationship between the two is like a passer-by in life, just a glance, then forget in the river’s lake. However, FactoryBeans are not alone. ObjcetFactory is a distant object. This article does not attempt to parse these two interfaces in detail, but you can think of them as incubators for beans of a specified type. But there’s a big difference.

BeanFactory & ApplicationContext

In everyday work we often refer to the BeanFactory as a container and the ApplicationContext as a context. I do not know whether we have thought about the relationship between the two. In the Spring Aware Interface family article, I explained in detail how to obtain the BeanFactory and ApplicationContext in the current runtime environment. You can find the answer in the code.

  • The configuration class
package com.spring.container;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.spring.container")
public class ContainerConfig {}Copy the code
  • Get both information
package com.spring.container;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/ * * *@Author: Raphael
 */
@Component
public class SpringIoc implements BeanFactoryAware.ApplicationContextAware {

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.err.println(System.identityHashCode(beanFactory));
        System.out.println(beanFactory.getClass().getName());
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException { System.err.println(System.identityHashCode(applicationContext)); System.out.println(applicationContext.getClass().getName()); }}Copy the code
  • Start the class
package com.spring.container;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/ * * *@Author: Raphael
 */
public class MainContainer {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context =
                newAnnotationConfigApplicationContext(ContainerConfig.class); context.close(); }}Copy the code
  • The results of

It is obvious that not only are they not the same object, they are of different types. See here most people’s perception is broken, because subconsciously they think the two are the same thing. The fact that the family did not even have an inheritance relationship directly shattered the illusion of another wave of people. Let’s take a look at the UML class diagram for both.

How many containers?

The astute have already seen the paradox, recognizing that there should be one and only one root container for Spring. But these are clearly two unrelated objects. The official Spring documentation describes the relationship as follows:

In short, BeanFactory provides the configuration framework and basic functionality, and ApplicationContext adds more enterprise-specific functionality. ApplicationContext is a complete superset of BeanFactory.

Can we get the root container in ApplicationContext? And god said, let there be light, so getAutowireCapableBeanFactory ().

package com.spring.container;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/ * * *@Author: Raphael
 */
@Component
public class SpringIoc implements BeanFactoryAware.ApplicationContextAware {

    private BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
        System.err.println(System.identityHashCode(beanFactory));
        System.out.println(beanFactory.getClass().getName());
    }

    // Print the result of the comparison between two objects directly
    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        AutowireCapableBeanFactory factory =
                applicationContext.getAutowireCapableBeanFactory();
        System.err.println(factory.hashCode());
        System.out.println(factory.getClass().getName());
        System.out.println("Are they equal?"+ (factory == beanFactory)); }}Copy the code

The verification results fully support the official instructions.

DefaultListableBeanFactory

The official definition of him is:

Spring’s {@ link ConfigurableListableBeanFactory}, {@ link BeanDefinitionRegistry} the default implementation

A mature bean factory is based on bean definition metadata and can be extended with a post-processor

Front of light is the BeanFactory, carry something DefaultListableBeanFactory, clearly is three people’s movie, but I still can not have a name. So DefaultListableBeanFactory object is to produce? A new problem has come to haunt me. The answer has to do with the initialization of the IOC container, which I won’t cover here. We simply analyze the journey DefaultListableBeanFactory produce objects. We call the following constructor in MainContainer:

public AnnotationConfigApplicationContext(Class
       ... annotatedClasses) {
    this(a); register(annotatedClasses); refresh(); }Copy the code

Because AnnotationConfigApplicationContext inherited GenericApplicationContext, so the superclass constructor will call at the same time, the container object is born at this time.

public GenericApplicationContext(a) {
    this.beanFactory = new DefaultListableBeanFactory();
}
Copy the code

Refresh () then calls obtainFreshBeanFactory().

protected ConfigurableListableBeanFactory obtainFreshBeanFactory(a) {
    refreshBeanFactory();
    return getBeanFactory();
}
Copy the code

GetBeanFactory () is defined AbstractApplicationContext abstract methods. And by GenericApplicationContext implementation.

public final ConfigurableListableBeanFactory getBeanFactory(a) {
    return this.beanFactory;
}
Copy the code

There actually is a method to construct their own object is returned to the AnnotationConfigApplicationContext. The mystery of the container object’s origin was finally solved when we traced it to this level. The reason that ApplicationContext has Beanfactory capability is that it delegates operations to its own internal container objects. Here’s an example:

public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
    assertBeanFactoryActive();
    return getBeanFactory().getBean(name, requiredType);
}
Copy the code

He doesn’t actually have a detailed implementation of this method here, but instead gets its own internal container object via getBeanFactory() and hands it off to TA to implement. Now the thread should be clear enough. Spring source code is a comprehensive design pattern, here is actually the use of composite pattern.

The difference between

There are official summaries of both

Org. Springframework. Beans and org. Springframework. The context is the basis of the framework of the Spring IoC container. The BeanFactory interface provides an advanced configuration mechanism for managing any type of object. ApplicationContext is a subinterface.

Added the following features:

  • Easy integration with Spring’s AOP capabilities
  • Message resource processing (for internationalization)
  • Activity released
  • Application layer specific context

Spring official documentation, really not ready to see?

Finally: long flowers, full moon, long life