乐趣区

关于spring: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<String> beanDefinitionNames = new ArrayList<>(256);

private final Map<String, BeanDefinition> 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<String> 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<String> 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 的依赖

退出移动版