Spring: Bean 注册 - BeanDefinitionRegistry

1.美图

在这里插入图片描述

2.概述

BeanDefinitionRegistry ,该类的作用主要是向注册表中注册 BeanDefinition 实例,完成 注册的过程。

BeanDefinitionRegistry 对象: 抽象出 bean 的注册逻辑。registerBeanDefinition、removeBeanDefinition、getBeanDefinition 等注册管理 BeanDefinition 的方法。

3.源码

public interface BeanDefinitionRegistry extends AliasRegistry {

    // 关键 -> 往注册表中注册一个新的 BeanDefinition 实例 
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException;

    // 移除注册表中已注册的 BeanDefinition 实例
    void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    // 从注册中取得指定的 BeanDefinition 实例
    BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    // 判断 BeanDefinition 实例是否在注册表中(是否注册)
    boolean containsBeanDefinition(String beanName);

    // 取得注册表中所有 BeanDefinition 实例的 beanName(标识)
    String[] getBeanDefinitionNames();

    // 返回注册表中 BeanDefinition 实例的数量
    int getBeanDefinitionCount();

    // beanName(标识)是否被占用
    boolean isBeanNameInUse(String beanName);

}

再来看它的继承关系:

在这里插入图片描述

4.DefaultListableBeanFactory

该类是 BeanDefinitionRegistry 接口的基本实现类,但同时也实现其他了接口的功能,这里只探究下其关于注册 BeanDefinition 实例的相关方法 。

首先来看它的成员变量:

// 关键-> 注册表,由 BeanDefinition 的标识 (beanName) 与其实例组成
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, bean>(64);

// 标识(beanName)集合
private final List<String> beanDefinitionNames = new ArrayList<String>(64);

再来看 BeanDefinitionReaderUtilsregisterBeanDefinition 方法。该方法的主要作用是调用注册器(DefaultListableBeanFactory)完成注册过程。

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
    throws BeanDefinitionStoreException {

    Assert.hasText(beanName, "Bean name must not be empty");
    Assert.notNull(beanDefinition, "BeanDefinition must not be null");

    if (beanDefinition instanceof AbstractBeanDefinition) {
        try {
            // BeanDefinition 校验
            ((AbstractBeanDefinition) beanDefinition).validate();

        }catch (BeanDefinitionValidationException ex) {
            // 抛出异常...
        }
    }

    BeanDefinition oldBeanDefinition;

    oldBeanDefinition = this.beanDefinitionMap.get(beanName);
    if (oldBeanDefinition != null) {
        if (!isAllowBeanDefinitionOverriding()) {
            // 抛出异常...
        }else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
            // 日志输出...
        }
        else if (!beanDefinition.equals(oldBeanDefinition)) {
            // 日志输出...
        }
        else {
            // 日志输出...
        }
    }else {
        // 添加标识进 List
        this.beanDefinitionNames.add(beanName);
        this.manualSingletonNames.remove(beanName);
        this.frozenBeanDefinitionNames = null;
    }

    // 关键 -> 添加进 map
    this.beanDefinitionMap.put(beanName, beanDefinition);

    if (oldBeanDefinition != null || containsSingleton(beanName)) {
        resetBeanDefinition(beanName);
    }
}

观察代码可以发现该方法最重要的步骤其实就是:

this.beanDefinitionMap.put(beanName, beanDefinition);

也就是向注册表中(beanDefinitionMap)添加 BeanDefinition 实例,完成注册的过程。

5.案例

5.1 自定义了一个BeanDefinitionRegistry

BeanDefinition实例化之后,会有"一个东西"将这些实例化的BeanDefinition交给BeanDefinitionRegistry并调用下面两个方法

public class MyBeanDefinitionRegistry implements BeanDefinitionRegistry {
	//其他Override方法省略
	@Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {
		System.out.println(String.format("调用方法:%s", "registerBeanDefinition"));
	}

	@Override
	public boolean containsBeanDefinition(String beanName) {
		System.out.println(String.format("调用方法:%s", "containsBeanDefinition"));
		return false;
	}
}

5.2 测试

package com.spring.boot.bean.registry;

import org.junit.Test;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;

import static org.junit.Assert.*;

public class MyBeanDefinitionRegistryTest {

    /**
     * 测试结果:
     * 调用方法:containsBeanDefinition
     * 调用方法:registerBeanDefinition
     * 调用方法:containsBeanDefinition
     * 调用方法:registerBeanDefinition
     * 调用方法:containsBeanDefinition
     * 调用方法:registerBeanDefinition
     * 调用方法:containsBeanDefinition
     * 调用方法:registerBeanDefinition
     * 调用方法:containsBeanDefinition
     * 调用方法:registerBeanDefinition
     */
    @Test
    public void registerBeanDefinition() {
        MyBeanDefinitionRegistry myBeanDefinitionRegistry = new MyBeanDefinitionRegistry();
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(myBeanDefinitionRegistry);
        scanner.scan("com.spring.boot.bean.registry");
    }
}

测试方法中的scanner就是我上面所说的"一个东西",我猜应该有很多类似这样的类,它会扫描基础包名下面所有有Company注解的类及其派生类,然后将这些类封装成BeanDefinition,每生成一个BeanDefinition,都会再将这个BeanDefinition交给我自己定义的MyBeanDefinitionRegistry方法,然后调用containsBeanDefinition方法,再调用registerBeanDefinition注册

发布了1089 篇原创文章 · 获赞 451 · 访问量 136万+

猜你喜欢

转载自blog.csdn.net/qq_21383435/article/details/104141479