Spring 水滴石穿(三) 工厂实现之bean定义注册BeanDefinitionRegistry

BeanDefinitionRegistry接口

这个接口扩展了上文提到的别名注册接口,提供了bean定义的注册,注销等功能

public interface BeanDefinitionRegistry extends AliasRegistry {
    //注册bean定义,可能抛出异常
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException;

    //注销bean定义,可能抛出异常
    void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    //获取bean定义
    BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    //是否包含bean定义
    boolean containsBeanDefinition(String beanName);

    //获取所有bean定义的名字
    String[] getBeanDefinitionNames();

    //返回bean定义的总数
    int getBeanDefinitionCount();

    //是否给定的bean在使用了
    boolean isBeanNameInUse(String beanName);

}

DefaultListableBeanFactory实现

虽然还有一些别的实现,但我们beanFactory的分析整个都是基于DefaultListableBeanFactory的继承体系来分析的,可以看到这个类直接实现了我们的bean定义注册接口,下面分析它的相关实现

与bean定义有关的属性

private volatile List beanDefinitionNames = new ArrayList<>(256);

private final Map beanDefinitionMap = new ConcurrentHashMap<>(256);

registerBeanDefinition

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

        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
            //验证bean定义
                ((AbstractBeanDefinition) beanDefinition).validate();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }

        BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
        if (existingDefinition != null) {
        //是否允许bean定义重写是可以配置的
            if (!isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
            }
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        else {
        //是否已经创建了bean
            if (hasBeanCreationStarted()) {
                // Cannot modify startup-time collection elements anymore (for stable iteration)
                synchronized (this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    removeManualSingletonName(beanName);
                }
            }
            else {
                // Still in startup registration phase
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                //移除手动单例名字,将注册的bean定义优先级更高
                removeManualSingletonName(beanName);
            }
            //无论如何,解冻已冻结的bean定义
            this.frozenBeanDefinitionNames = null;
        }

        //如果本来就存在bean定义,或者这个bean已经处于创建中了,需要重置bean定义
        if (existingDefinition != null || containsSingleton(beanName)) {
            resetBeanDefinition(beanName);
        }
        else if (isConfigurationFrozen()) {
            clearByTypeCache();
        }
    }

有几个要注意的地方
1.((AbstractBeanDefinition) beanDefinition).validate()

bean定义除了这个抽象bean定义还是基于注解的bean定义,只有在抽象bean定义的时候才会去做验证,后面在分析这个方法
2.在往map添加新数据前有个hasBeanCreationStarted方法
如果都没有创建好的bean,说明当前一定没有对beanName集合的遍历,要知道遍历的时候去添加数据是不稳定的,有可能抛出并发修改异常,所以这里通过这个方法来判断。个人理解,深入分析以后也没发觉这个方法是线程安全的,感觉又不是这个原因?
3.后续处理:旧的bean定义存在,或者单例的bean已经在创建中
这种情况意味着对旧的bean定义重写了,但什么时候会出现没有旧的bean定义但是单例bean已经在创建了呢?可以看到有一条关键路径就是重置bean定义,这里可以认为是做一些清理工作,比如移除合并后的bean定义
protected void resetBeanDefinition(String beanName) {
        //如果已经被创建,移除合并后的bean定义
        clearMergedBeanDefinition(beanName);

        //移除缓存的单例
        destroySingleton(beanName);

        //通知所有的后置处理器,指定的bean定义被重置了
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            if (processor instanceof MergedBeanDefinitionPostProcessor) {
                ((MergedBeanDefinitionPostProcessor) processor).resetBeanDefinition(beanName);
            }
        }

        // 递归重置所有的子bean定义
        for (String bdName : this.beanDefinitionNames) {
            if (!beanName.equals(bdName)) {
                BeanDefinition bd = this.beanDefinitionMap.get(bdName);
                // Ensure bd is non-null due to potential concurrent modification of beanDefinitionMap.
                if (bd != null && beanName.equals(bd.getParentName())) {
                    resetBeanDefinition(bdName);
                }
            }
        }
    }

removeBeanDefinition

这里类似于注册,不再分析

public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {

        BeanDefinition bd = this.beanDefinitionMap.remove(beanName);
        if (bd == null) {
            throw new NoSuchBeanDefinitionException(beanName);
        }
        if (hasBeanCreationStarted()) {
            synchronized (this.beanDefinitionMap) {
                List updatedDefinitions = new ArrayList<>(this.beanDefinitionNames);
                updatedDefinitions.remove(beanName);
                this.beanDefinitionNames = updatedDefinitions;
            }
        }
        else {
            // Still in startup registration phase
            this.beanDefinitionNames.remove(beanName);
        }
        this.frozenBeanDefinitionNames = null;

        resetBeanDefinition(beanName);
    }

getBeanDefinitionNames

这里有意思的是如果已冻结的bean定义列表有数据,就返回这个,否则就返回实时的bean定义列表数据,至于为何这么做有待思考。

    public String[] getBeanDefinitionNames() {
        String[] frozenNames = this.frozenBeanDefinitionNames;
        if (frozenNames != null) {
            return frozenNames.clone();
        }
        else {
            return StringUtils.toStringArray(this.beanDefinitionNames);
        }
    }

isBeanNameInUse

这个方法实现并不在DefaultListableBeanFactory中,因为DefaultListableBeanFactory还继承了AbstractBeanFactory,在它的抽象父类中实现了该方法,这也说明接口中的方法不一定要在一个类中全部实现,只要能够保证通过继承实现也是可以的!

public boolean isBeanNameInUse(String beanName) {
        return isAlias(beanName) || containsLocalBean(beanName) || hasDependentBean(beanName);
    }

这个逻辑并不复杂,也就是判断beanName是否被别名占用了,容器本地是否包含了beanName,beanName是否是某一个bean的依赖

你可能感兴趣的:(spring,java)