3.1.2AbstrctBeanDefiniton属性 ~ 3.1.5通知监听器解析及注册完成

3.1.2AbstrctBeanDefiniton属性
至此我们完成了XML文档中的bean标签到GenericBeanDefinition对象的转换,也就是说到这里,XML中所有配置都可以在GenericBeanDefinition实例中找到对于的位置。
GenericBeanDefinition只是子类实现,大部分属性都保存在了AbstractBeanDefinition的属性中。
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
        implements BeanDefinition, Cloneable {

    /**
     * Constant for the default scope name: {@code ""}, equivalent to singleton
     * status unless overridden from a parent bean definition (if applicable).
     */
    public static final String SCOPE_DEFAULT = "";

    /**
     * Constant that indicates no external autowiring at all.
     * @see #setAutowireMode
     */
    public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;

    /**
     * Constant that indicates autowiring bean properties by name.
     * @see #setAutowireMode
     */
    public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;

    /**
     * Constant that indicates autowiring bean properties by type.
     * @see #setAutowireMode
     */
    public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;

    /**
     * Constant that indicates autowiring a constructor.
     * @see #setAutowireMode
     */
    public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;

    /**
     * Constant that indicates determining an appropriate autowire strategy
     * through introspection of the bean class.
     * @see #setAutowireMode
     * @deprecated as of Spring 3.0: If you are using mixed autowiring strategies,
     * use annotation-based autowiring for clearer demarcation of autowiring needs.
     */
    @Deprecated
    public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;

    /**
     * Constant that indicates no dependency check at all.
     * @see #setDependencyCheck
     */
    public static final int DEPENDENCY_CHECK_NONE = 0;

    /**
     * Constant that indicates dependency checking for object references.
     * @see #setDependencyCheck
     */
    public static final int DEPENDENCY_CHECK_OBJECTS = 1;

    /**
     * Constant that indicates dependency checking for "simple" properties.
     * @see #setDependencyCheck
     * @see org.springframework.beans.BeanUtils#isSimpleProperty
     */
    public static final int DEPENDENCY_CHECK_SIMPLE = 2;

    /**
     * Constant that indicates dependency checking for all properties
     * (object references as well as "simple" properties).
     * @see #setDependencyCheck
     */
    public static final int DEPENDENCY_CHECK_ALL = 3;

    /**
     * Constant that indicates the container should attempt to infer the
     * {@link #setDestroyMethodName destroy method name} for a bean as opposed to
     * explicit specification of a method name. The value {@value} is specifically
     * designed to include characters otherwise illegal in a method name, ensuring
     * no possibility of collisions with legitimately named methods having the same
     * name.
     * <p>Currently, the method names detected during destroy method inference
     * are "close" and "shutdown", if present on the specific bean class.
     */
    public static final String INFER_METHOD = "(inferred)";


    @Nullable
    private volatile Object beanClass;

    /**
     * bean的作用范围,对应bean属性scope
     * 默认=空字符串=单例singleton,通过isSingleton()方法判断
     */
    @Nullable
    private String scope = SCOPE_DEFAULT;

    /**
     * 是否是抽象,对应bean属性abstract
     */
    private boolean abstractFlag = false;

    /**
     * 是否延迟加载,对应bean属性lazy-init
     */
    @Nullable
    private Boolean lazyInit;

    /**
     * 自动注入模式,对应bean属性autowire。默认不
     */
    private int autowireMode = AUTOWIRE_NO;

    /**
     * 依赖检查,Spring3.0后弃用这个属性
     */
    private int dependencyCheck = DEPENDENCY_CHECK_NONE;

    /**
     * 用来表示一个bean的实例化依靠另一个bean先实例化,对应bean属性depend-on
     */
    @Nullable
    private String[] dependsOn;

    /**
     * autowire-candidate属性设置为false,这样容器在查找自动装配时,将不考虑该bean。
     * 即它不会被考虑作为其他bean自动装配的候选者,但是该bean本身还是可以使用自动装配来注入其他bean
     */
    private boolean autowireCandidate = true;

    /**
     * 自动装配是当出现多个候选者时,将作为首选者,对应bean属性primary
     */
    private boolean primary = false;

    /**
     * 用来记录Qualifier,对应子元素qualifier
     */
    private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>();

    @Nullable
    private Supplier<?> instanceSupplier;

    /**
     * 允许访问非公开的构造器和方法,程序设置
     */
    private boolean nonPublicAccessAllowed = true;

    /**
     * 是否以一种宽松的模式解析构造函数,默认是true
     * 如果是false,则在如下情况
     * interface ITest()
     * class ITestImpl implement ITest{};
     * class Main{
     *     Main(ITest i){}
     *     Main(ITestImpl i){}
     * }
     * 抛出异常,因为Spring无法准确定位哪个构造函数
     * 程序异常
     */
    private boolean lenientConstructorResolution = true;

    /**
     * 用于调用工厂类
     */
    @Nullable
    private String factoryBeanName;

    /**
     * 用于实例化工厂类方法
     */
    @Nullable
    private String factoryMethodName;

    /**
     * 记录构造函数注入属性,对应bean属性constructor-arg
     */
    @Nullable
    private ConstructorArgumentValues constructorArgumentValues;

    /**
     * 普通属性集合
     */
    @Nullable
    private MutablePropertyValues propertyValues;

    /**
     * 方法重写的操作者,记录lookup-method、replace-method元素
     */
    private MethodOverrides methodOverrides = new MethodOverrides();

    /**
     * 初始化方法,对应bean属性init-method
     */
    @Nullable
    private String initMethodName;

    /**
     * 销毁方法,对应bean属性destroy-method
     */
    @Nullable
    private String destroyMethodName;

    /**
     * 是否执行init-method,程序设置
     */
    private boolean enforceInitMethod = true;

    /**
     * 是否执行destroy-method,程序设置
     */
    private boolean enforceDestroyMethod = true;

    /**
     * 是否用户定义的而不是应用程序本身定义的,创建AOP的时候为true,程序设置
     */
    private boolean synthetic = false;

    /**
     * 定义这个bean的应用,APPLICATION:用户,INFRASTRUCTURE:完全内部使用,与用户无关
     * SUPPORT某些复杂配置的一部分,程序设置
     */
    private int role = BeanDefinition.ROLE_APPLICATION;

    /**
     * bean的描述
     */
    @Nullable
    private String description;

    /**
     * 这个bean定义的资源
     */
    @Nullable
    private Resource resource;
}

 

3.1.3解析默认标签中的自定义标签
这里的自定义标签其实是属性,与上面说的不同,上面说的是Bean。
到这里我们完成了默认标签的解析与提取过程,或许涉及的内容太多,我们已经忘了从哪个函数开始,我们再次回顾下默认标签解析函数的起始函数
DefaultBeanDefinitionDocumentReader
/**
     * Process the given bean element, parsing the bean definition
     * and registering it with the registry.
     *
     * 1)首先委托BeanDefinitionDelegate类的parseBeanDefinitionElement方法进行元素解析,
     * 返回BeanDefinitionHolder类型的实例bdholder,
     * 经过这个方法后,bdholder已经包含了配置文件中的配置的各种属性(class、name、id、alias......)
     * 2)当返回的bdholder不为空的情况下若存在默认标签的子节点下有自定义属性,还需要对自定义标签解析。
     * 3)解析完成后,需要对解析后的bdholder进行注册。委托给BeanDefinitionReaderUtils的regiestBeanDefinition方法
     * 4)最后发出响应事件,通知相关监听器,这个bean已经加载完毕。
     *
     */
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    //委托BeanDefinitionDelegate类的parseBeanDefinitionElement方法进行元素解析,
    //返回BeanDefinitionHolder类型的实例bdholder,
    //经过这个方法后,bdholder已经包含了配置文件中的配置的各种属性(class、name、id、alias......)
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        //当返回的bdholder不为空的情况下若存在默认标签的子节点下有自定义属性,还需要对自定义标签解析。
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            // Register the final decorated instance.
            //注册bean
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
        }
        catch (BeanDefinitionStoreException ex) {
            getReaderContext().error("Failed to register bean definition with name '" +
                                     bdHolder.getBeanName() + "'", ele, ex);
        }
        // Send registration event.
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}
 
接下里我们解析bdHolder = delegate.decorateBeanDefinitionIfRequired(ele,bdHolder);
解析适用于下面的配置(bean使用的是默认的标签配置,但是其中的子元素却使用了自定义配置)
<bean id="test" class="MyTest">
    <mybean:user username="aaa" />
</bean>
让我们尽量解析
BeanDefinitionParserDelegate
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
    Element ele, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {

    BeanDefinitionHolder finalDefinition = originalDef;

    // Decorate based on custom attributes first.
    //遍历所有属性,看看是否有适用于修饰的属性
    NamedNodeMap attributes = ele.getAttributes();
    for (int i = 0; i < attributes.getLength(); i++) {
        Node node = attributes.item(i);
        finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
    }

    // Decorate based on custom nested elements.
    //遍历所有子节点,看看是否有适用于修饰子元素
    NodeList children = ele.getChildNodes();
    for (int i = 0; i < children.getLength(); i++) {
        Node node = children.item(i);
        if (node.getNodeType() == Node.ELEMENT_NODE) {
            finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
        }
    }
    return finalDefinition;
}

public BeanDefinitionHolder decorateIfRequired(
    Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {

    //获取自定义标签的命名空间
    String namespaceUri = getNamespaceURI(node);
    //对于非默认标签进行修饰
    if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
        //根据命名空间查找对应的处理器
        NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
        if (handler != null) {
            //进行修饰
            BeanDefinitionHolder decorated =
                handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
            if (decorated != null) {
                return decorated;
            }
        }
        else if (namespaceUri.startsWith("http://www.springframework.org/schema/")) {
            error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
        }
        else {
            // A custom namespace, not to be handled by Spring - maybe "xml:...".
            if (logger.isDebugEnabled()) {
                logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
            }
        }
    }
    return originalDef;
}
大致逻辑:
首先获取属性或者命名空间,以此来判断该元素或者属性是否是自定义标签,然后找出自定义类型所在的NamespaceHandler并进行进一步解析。在自定义标签解析那块(Bean)再说,现在暂时略过。
 
3.1.4注册解析BeanDefinition
解析了,装饰的也装饰了,BeanDefinition已经满足后续使用的要求了。是时候该注册了。 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
BeanDefinitionReaderUtils
/**
     * Register the given bean definition with the given bean factory.
     * @param definitionHolder the bean definition including name and aliases
     * @param registry the bean factory to register with
     * @throws BeanDefinitionStoreException if registration failed
     *
     * 对于配置文件,解析也解析完成了,装饰也装饰完了
     * 对于得到的BeanDefinition已经满足后续的使用要求了,唯一还剩下的就是注册了
     *
     */
public static void registerBeanDefinition(
    BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
    throws BeanDefinitionStoreException {

    // Register bean definition under primary name.
    //使用beanName作为唯一标识
    String beanName = definitionHolder.getBeanName();
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

    // Register aliases for bean name, if any.
    //注册所有别名
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        for (String alias : aliases) {
            registry.registerAlias(beanName, alias);
        }
    }
}
BeanDefinition会被注册到BeanDefinitionRegistry的实例中。注册分为两部分,通过beanName注册、通过别名注册。
1.通过beanName注册
嗯。没错,注册就是Spring将BeanDefinition放入map中,beanName作为key,只不过除此之外,它还做了点别的事情。
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 {
            /**
                 * 注册前最后一次校验,这里的校验不同于之前的XML文件校验
                 * 主要是对于AbstractBeanDefinition属性中的MethodOverrides校验,
                 * 校验MethodOverrides是否与工厂方法并存或者MethodOverrides对应的方法存不存在
                 */
            ((AbstractBeanDefinition) beanDefinition).validate();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                                                   "Validation of bean definition failed", ex);
        }
    }

    //beanDefinitionMap是全局变量,这里定会存在并发访问的情况。
    //使用CurreHashMap是不是可以解决这个情况?
    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    //处理已经注册的beanName的情况
    if (existingDefinition != null) {
        //如果对应的BeanName已经注册在配置中配置了bean不允许被覆盖,则抛出异常
        if (!isAllowBeanDefinitionOverriding()) {
            throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
        }
        else if (existingDefinition.getRole() < beanDefinition.getRole()) {
            // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
            if (logger.isInfoEnabled()) {
                logger.info("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            existingDefinition + "] with [" + beanDefinition + "]");
            }
        }
        else if (!beanDefinition.equals(existingDefinition)) {
            if (logger.isDebugEnabled()) {
                logger.debug("Overriding bean definition for bean '" + beanName +
                             "' with a different definition: replacing [" + existingDefinition +
                             "] with [" + beanDefinition + "]");
            }
        }
        else {
            if (logger.isTraceEnabled()) {
                logger.trace("Overriding bean definition for bean '" + beanName +
                             "' with an equivalent definition: replacing [" + existingDefinition +
                             "] with [" + beanDefinition + "]");
            }
        }
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }
    else {
        //alreadyCreated这个set集合不为空
        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 {    //alreadyCreated这个set集合为空
            // Still in startup registration phase
            //注册beanDefinition
            this.beanDefinitionMap.put(beanName, beanDefinition);
            //记录beanName
            this.beanDefinitionNames.add(beanName);
            removeManualSingletonName(beanName);
        }
        this.frozenBeanDefinitionNames = null;
    }

    if (existingDefinition != null || containsSingleton(beanName)) {
        //重制所有对beanName对应的缓存
        resetBeanDefinition(beanName);
    }
    else if (isConfigurationFrozen()) {
        clearByTypeCache();
    }
}

大致逻辑:

1.对AbstractBeanDefinition的校验,在解析XML文件时我们提过校验,但是此校验非彼校验,之前的校验时针对于XML格式的校验,而此时是针对AbstractBeandefinition的MethodOverrides属性的。

2.对beanName已经注册的情况的处理。如果设置了不允许bean的覆盖,则需要抛出异常,否则直接覆盖。

3.放入map(Map<String, BeanDefinition> beanDefinitionMap)缓存

4.清除解析之前留下的对应beanName的缓存。

2.通过别名注册BeanDefinition
SimpleAliasRegiestry
public void registerAlias(String name, String alias) {
    Assert.hasText(name, "'name' must not be empty");
    Assert.hasText(alias, "'alias' must not be empty");
    synchronized (this.aliasMap) {
        //如果beanName与alias相同的话不记录alias,并删除对应的alias
        if (alias.equals(name)) {
            this.aliasMap.remove(alias);
            if (logger.isDebugEnabled()) {
                logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
            }
        }
        else {
            String registeredName = this.aliasMap.get(alias);
            if (registeredName != null) {
                if (registeredName.equals(name)) {
                    // An existing alias - no need to re-register
                    return;
                }
                //如果alias不允许被覆盖则抛出异常
                if (!allowAliasOverriding()) {
                    throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +
                                                    name + "': It is already registered for name '" + registeredName + "'.");
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("Overriding alias '" + alias + "' definition for registered name '" +
                                 registeredName + "' with new target name '" + name + "'");
                }
            }
            //当A->B存在时,若再次出现A->C->B时候则会抛出异常
            //当beanName A 指定 别名 B时候
            checkForAliasCircle(name, alias);
            this.aliasMap.put(alias, name);
            if (logger.isTraceEnabled()) {
                logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
            }
        }
    }
}
大致逻辑:
1.若alias与beanName名称相同则不需要处理并删除alias
2.若alias已经被使用并被指定列一个beanName则需要用户设置覆盖属性。
3.alias循环检查。
4.注册alias。
 
3.1.5通知监听器解析及注册完成
通过代码 getReaderContext().fireComponentRegistered(new BeanComponent-Definition(bdHolder))完成此工作。这里的实现只为扩展,当程序人员需要对BeanDefinition事件进行监听的时候,可以通过注册监听器的方式并将处理逻辑写入监听器中,目前Spring中并没有对此事件做任何逻辑处理。





posted @ 2021-01-13 16:54  _Shing  阅读(218)  评论(0)    收藏  举报