Spring talks about: What is BeanFactory? (With source code)

Preface

When it comes to Spring, it always reminds people of the IOC container for the first time, and the top-level core interface of the IOC container is our BeanFactory. If we can understand the architecture of the BeanFactory, we must have a clearer understanding of the overall context of Spring, so The main research directions of this article are as follows:

  • What is the architecture of BeanFactory?
  • Where does Bean's meta-information come from?
  • How does BeanFactory produce beans?

BeanFactory's architecture

Let's first take a look at which subclasses implement it

Spring talks about: What is BeanFactory?  (With source code)

 

The ApplicationContext has been explained in detail in the previous article, and the underlying implementation class DefaultListableBeanFactory has naturally become the starting point of our exploration. In order to give us a better look and feel, the following is a pure BeanFactoryUML diagram:

Spring talks about: What is BeanFactory?  (With source code)

 

We can see that the interfaces implemented by DefaultListableBeanFactory are:

  • SingletonBeanRegistry: Defines operations related to the singleton buffer pool, such as registering beans in the singleton buffer pool
  • ConfigurableBeanFactory: Configurable BeanFactory, which defines various configuration capabilities, such as bean scope, bean classLoader, adding bean post processor, setting bean creation state, destroying bean, etc.
  • AutowireCapableBeanFactory: A BeanFactory that can perform automatic assembly. This is probably the BeanFactory we are most familiar with. It defines the type of automatic assembly (byName/byType), createBean, autowireBean, automatic assembly attributes, populateBean, initializeBean, and methods related to the bean life cycle Will be reflected here
  • ListableBeanFactory: an enhancement to BeanFactory, defines a series of methods to obtain bean or beanName according to beanType
  • ConfigurableListableBeanFactory: an enhancement to ConfigurableBeanFactory, defines methods such as ignoring bean types, caching bean definitions, and pre-instantiating singleton beans
  • BeanDefinitionRegistry: bean definition register, defines methods related to bean definition

If the above interface reflects the functions of DefaultListableBeanFactory, then a series of classes it inherits is the realization of these functions:

  • DefaultSingletonBeanRegistry: Singleton bean registrar, which defines a three-level cache, which is actually three Map attributes
  • FactoryBeanRegistrySupport: Provides support for FactoryBean
  • AbstractBeanFactory: A series of functions for operating the IOC container are implemented, but the final createBean is still handed over to the subclass AbstractAutowireCapableBeanFactory to complete
  • AbstractAutowireCapableBeanFactory: realizes the function of creating beans, all functions related to creating beans are here
  • DefaultListableBeanFactory: Based on the functions of the above parent class, it implements the ConfigurableBeanFactory and BeanDefinitionRegistry interfaces, and defines some Maps that store Bean definition related information

> Seeing this, I must have a general understanding of DefaultListableBeanFactory, then the question is, how should we get a bean from the container? Is it only necessary to register a bean definition through BeanDefinitionRegistry, and then createBean through AutowireCapableBeanFactory? It looks like this:

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
RootBeanDefinition beanDefinition = new RootBeanDefinition(Wheel.class);
beanFactory.registerBeanDefinition("wheel",beanDefinition);
beanFactory.getBean("wheel", Wheel.class);

Where does Bean's meta-information come from?

We now know the general function of DefaultListableBeanFactory. We found that when we want to create a Bean, we always cannot do without a term: Bean definition. So what exactly is this Bean definition?

BeanDefinition is actually an interface, not a specific class, we can also look at its UML diagram:

Spring talks about: What is BeanFactory?  (With source code)

 

It can be found that the design pattern that uses the template method here extends many subclasses, among which the most commonly used one is RootBeanDefinition, which mainly contains the following attributes:

Spring talks about: What is BeanFactory?  (With source code)

 

The information we define with the Bean registered in the container is probably the case. When the BeanFactory produces the Bean, you can clearly know what the Bean's class is, what the scope is, whether it is lazy, what the init method is, etc.

> Hey, if it is the simplest bean, it seems that it can be done directly through reflection~

The specific structure is clear, let's take a look at the registration process

Let’s start with Demo

public static void main(String[] args) {
    //创建一个DefaultListableBeanFactory实例
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    //创建一个BeanDefinition
    RootBeanDefinition beanDefinition = new RootBeanDefinition(Wheel.class);
    //将BeanDefinition注册到容器中
    beanFactory.registerBeanDefinition("wheel",beanDefinition);
}
public static class Wheel {
}

Create BeanDefinition

public RootBeanDefinition(@Nullable Class<!--?--> beanClass) {
    //初始化父类
    super();
    //将beanClass赋值给this.BeanClass
    setBeanClass(beanClass);
}

Initialize the parent class

//将其中一部分属性赋予默认值
autowireCandidate = true;
primary = false;
protected AbstractBeanDefinition() {    this(null, null);
}protected AbstractBeanDefinition(@Nullable ConstructorArgumentValues cargs, @Nullable MutablePropertyValues pvs) {    this.constructorArgumentValues = cargs;
    this.propertyValues = pvs;
}

Register BeanDefinition into the container

//除去校验逻辑,注册时只做了这两步操作
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);

Seeing this, the big guy might be full of questions? what? That's it? Is there no step to populate attributes? Hey, BeanFactory is a pure factory, which is only responsible for producing Beans. It does not have the function of assembling (designing) BeanDefinition. Professional matters are still left to professional people, and design matters are still completed by ApplicationContext.

How to complete a BeanDefinition in the ApplicationContext? Remember that there was such a piece of code when pre-launched to register the configuration class in the container? The following code is the summary part in AnnotatedBeanDefinitionReader#doRegisterBean:

<t> void doRegisterBean(Class<t> annotatedClass, @Nullable Supplier<t> instanceSupplier, @Nullable String name,
                        @Nullable Class<!--? extends Annotation-->[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
	//.......代码    //处理普通的bean定义注解,@Lazy @Primary @DependsOn @Role @Description    AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);    //......代码   } 

The non-configured Bean is completed by the configuration class post processor ConfigurationClassPostProcessor#processConfigBeanDefinitions registered at pre-start. The following code is the summary part of ClassPathBeanDefinitionScanner#doScan. The detailed call chain will be explained in the following article

//传入我们配置类的包路径
protected Set<beandefinitionholder> doScan(String... basePackages) {		Set<beandefinitionholder> beanDefinitions = new LinkedHashSet<>();
		for (String basePackage : basePackages) {
            //寻找到所有标识了@Component注解的BeanDefinition
			Set<beandefinition> candidates = findCandidateComponents(basePackage);			for (BeanDefinition candidate : candidates) {
				//....省略代码
				if (candidate instanceof AbstractBeanDefinition) {
                    //处理BeanDefinition
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);				}				if (candidate instanceof AnnotatedBeanDefinition) {
 //处理普通的bean定义注解,@Lazy @Primary @DependsOn @Role @Description
                    AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);				}                //...省略代码
                //将BeanDefinition注册到容器中
                registerBeanDefinition(definitionHolder, this.registry);
            }	}

Processing BeanDefinition

protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
	//设置默认值
    beanDefinition.applyDefaults(this.beanDefinitionDefaults);
    //这里默认为空
    if (this.autowireCandidatePatterns != null) {
        beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName));
    }}

Set default

public void applyDefaults(BeanDefinitionDefaults defaults) {
    //默认为null
    Boolean lazyInit = defaults.getLazyInit();    if (lazyInit != null) {
        setLazyInit(lazyInit);    }    //默认为0
    setAutowireMode(defaults.getAutowireMode());    //默认为0
    setDependencyCheck(defaults.getDependencyCheck());    //默认为null
    setInitMethodName(defaults.getInitMethodName());    setEnforceInitMethod(false);
    //默认为null
    setDestroyMethodName(defaults.getDestroyMethodName());    setEnforceDestroyMethod(false);
}

Processing common bean definition annotations

public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
    processCommonDefinitionAnnotations(abd, abd.getMetadata());
}
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
    	//从元数据中取出该注解的属性列表,不为空说明有标识该注解
		AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
		if (lazy != null) {
			abd.setLazyInit(lazy.getBoolean("value"));
		}
		else if (abd.getMetadata() != metadata) {
			lazy = attributesFor(abd.getMetadata(), Lazy.class);
			if (lazy != null) {
				abd.setLazyInit(lazy.getBoolean("value"));
			}
		}
		//判断元数据中是否有该注解
		if (metadata.isAnnotated(Primary.class.getName())) {
			abd.setPrimary(true);
		}
		AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
		if (dependsOn != null) {
			abd.setDependsOn(dependsOn.getStringArray("value"));
		}
		AnnotationAttributes role = attributesFor(metadata, Role.class);
		if (role != null) {
			abd.setRole(role.getNumber("value").intValue());
		}
		AnnotationAttributes description = attributesFor(metadata, Description.class);
		if (description != null) {
			abd.setDescription(description.getString("value"));
		}
	}

attributesFor(metadata, Lazy.class)

static AnnotationAttributes attributesFor(AnnotatedTypeMetadata metadata, Class<!--?--> annotationClass) {
    return attributesFor(metadata, annotationClass.getName());}static AnnotationAttributes attributesFor(AnnotatedTypeMetadata metadata, String annotationClassName) {    //metadata为beanClass的注解元数据,存放了该类所配置的所有注解    //annotationClassName为需要寻找的注解名称    return AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(annotationClassName, false));}default Map<string, object> getAnnotationAttributes(String annotationName,
                                                    boolean classValuesAsString) {    //遍历元数据中的所有注解    MergedAnnotation<annotation> annotation = getAnnotations().get(annotationName,
                                                                   null, MergedAnnotationSelectors.firstDirectlyDeclared());    //不存在则返回null,否则返回一个map    if (!annotation.isPresent()) {        return null;    }    return annotation.asAnnotationAttributes(Adapt.values(classValuesAsString, true));}

> The above is the logic of scanning the @Component annotation class to parse the metadata and filling the attributes. The BeanDefinition registered in the @Bean mode in the configuration class is filled with attributes in ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(configClasses)

How does BeanFactory produce beans?

Now that we know the specific structure of a BeanDefinition and how it is generated and registered in the BeanFactory, how does the BeanFactory use it to produce Beans? A rough flow chart of createBean is attached below. The specific details will be explained in the IOC container startup process.

Spring talks about: What is BeanFactory?  (With source code)

 

> So the relevant content about BeanFactory is here, I hope you can gain something, the next part will officially enter the startup process of the Spring IOC container!

Original link: https://my.oschina.net/qiketime/blog/4667886
If you think this article is helpful to you, you can like to follow it to support it, or you can click on my homepage to follow my public account , there are more technical dry goods on it Articles and related materials are shared, everyone learns and progresses together!

Guess you like

Origin blog.csdn.net/weixin_50205273/article/details/109015151