资讯专栏INFORMATION COLUMN

Spring源码一(容器的基本实现3)

qylost / 1983人阅读

摘要:前言继续前一章,接下来解析标签的的属性信息及的注册。不过只不过是一个子类的实现,而大部分属性都是保存到了中去了。也就是函数中的代码的解析了。通过注册对于的注册,或许很多人认为的方式就是将直接放入中就好了,使用作为。

前言:继续前一章,接下来解析Bean标签的的属性信息及bean的注册。 1. 解析当前bean标签的内容
当我们创建了bean信息的承载实例之后, 便可以进行bean信息的各种属性的解析了, 首先我们进入parseBeanDefinitionAttributes方法,parseBeanDefinitionAttributes方法是对element所有元素属性进行解析:
/**
 * Apply the attributes of the given bean element to the given bean * definition.
 * @param ele bean declaration element
 * @param beanName bean name
 * @param containingBean containing bean definition
 * @return a bean definition initialized according to the bean element attributes
 */
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
        @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {

    if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
        error("Old 1.x "singleton" attribute in use - upgrade to "scope" declaration", ele);
    }
    else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
        bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
    }
    else if (containingBean != null) {
        // Take default from containing bean in case of an inner bean definition.
        bd.setScope(containingBean.getScope());
    }

    if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
        bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
    }

    String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
    if (DEFAULT_VALUE.equals(lazyInit)) {
        lazyInit = this.defaults.getLazyInit();
    }
    bd.setLazyInit(TRUE_VALUE.equals(lazyInit));

    String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
    bd.setAutowireMode(getAutowireMode(autowire));

    if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
        String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
        bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
    }

    String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
    if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) {
        String candidatePattern = this.defaults.getAutowireCandidates();
        if (candidatePattern != null) {
            String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
            bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
        }
    }
    else {
        bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
    }

    if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
        bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
    }

    if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
        String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
        bd.setInitMethodName(initMethodName);
    }
    else if (this.defaults.getInitMethod() != null) {
        bd.setInitMethodName(this.defaults.getInitMethod());
        bd.setEnforceInitMethod(false);
    }

    if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
        String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
        bd.setDestroyMethodName(destroyMethodName);
    }
    else if (this.defaults.getDestroyMethod() != null) {
        bd.setDestroyMethodName(this.defaults.getDestroyMethod());
        bd.setEnforceDestroyMethod(false);
    }

    if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
        bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
    }
    if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
        bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
    }

    return bd;
}

通过以上代码我们可以发现, 在1.0版本会有一个singleton 不过呢, 这个很快就被取代掉了, 使用的话会提示错误信息, 在新的版本里, 我们使用了scpoe=“singleton” 作为一个新的使用方式, 我们都知道在spring中,所创建的bean 都被认为默认认为是单例的,并且通过scope这个关键字,即scope="singleton"。另外scope还有prototype、request、session、global session作用域。scope="prototype"多例。 scope就是一个作用域,如果有不太理解的话,可以参照一下:Spring scope作用域详解。在这里只是看了一下scope标签的解析, 那么肯定还会有很多的属性, 我们用或者没有用过, 但是就不做讲解了, 我们知道spring是如何去做的就好了。

2. 解析bean中的元数据, meta中的内容

例如:


  

通常我们通过配置文件使用spring的时候, 我们会用到meta这个标签,这个标签中门会配置上, key, 和value这两个属性,

public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
    NodeList nl = ele.getChildNodes();
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) {
            Element metaElement = (Element) node;
            String key = metaElement.getAttribute(KEY_ATTRIBUTE);
            String value = metaElement.getAttribute(VALUE_ATTRIBUTE);
            BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
            attribute.setSource(extractSource(metaElement));
            attributeAccessor.addMetadataAttribute(attribute);
        }
    }
}

通过代码, 我们可以发现, spring通过解析得到的Element树对象去得到子节点, 然后便利子节点, 并且取得meta元素的key值和value的知值,然后将其存储在attributeAccessor中。由此推测, 其他的子集标签也会是通过这种方式去加载, 并且这也符合我们的预期。

3. 重提AbstractBeanDefinition属性
至此我们便完成了对xml文档到GenericBenaDefinition的转换, 也就是说我们将xml里面所有的配置都保存到了一个java实例中去了。不过GenericBenaDefinition只不过是一个子类的实现, 而大部分属性都是保存到了AbstractBeanDefinition中去了。

当打开AbstractBeanDefinition这个类我们可以发现, 几乎所有同bean配置的属性都已经在这个类中进行了定义:

public static final String SCOPE_DEFAULT = "";

/**
 * Constant that indicates no 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;

这里就不进行一一列举了。

4.注册解析的BeanDefinition

对于配置文件的解析已经完成了,我们得到了整个配置的内容, 接下来呢Spring做的事就是对注册了。也就是processBeanDeefinition函数中的registerBeanDefinition(bdHolder, getReaderContext(),getRegistry())代码的解析了。

/**
 * 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
 */
public static void registerBeanDefinition(
        BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
        throws BeanDefinitionStoreException {

    // Register bean definition under primary name.
    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类型的实例registry, 而对于beanDefinition的注册分成了两部分:通过beanName的注册以及通过别名注册。

通过beanName 注册BeanDefinition

对于beanDefinition的注册, 或许很多人认为的方式就是将beanDefinition直接放入map中就好了, 使用beanName作为key。确实,Spring就是这么做的, 只不过除此之外, 它还做了点别的事情。
@Override

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 {
            ((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) {
        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 {
        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;
                if (this.manualSingletonNames.contains(beanName)) {
                    Set updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
                    updatedSingletons.remove(beanName);
                    this.manualSingletonNames = updatedSingletons;
                }
            }
        }
        else {
            // Still in startup registration phase
            this.beanDefinitionMap.put(beanName, beanDefinition);
            this.beanDefinitionNames.add(beanName);
            this.manualSingletonNames.remove(beanName);
        }
        this.frozenBeanDefinitionNames = null;
    }

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

通过上面的代码可以发现, Spring确实将beanName放到了一个名字叫做beanDefinitionMap这样的一个map之中,这个map的类型是线程安全的ConcurrentHashMap, 而在这之前,只不过是做了一些验证。而对于通过别名进行注册的BeanDefinition, 代码是这样的:
@Override

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) {
        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;
                }
                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 + """);
                }
            }
            checkForAliasCircle(name, alias);
            this.aliasMap.put(alias, name);
            if (logger.isTraceEnabled()) {
                logger.trace("Alias definition "" + alias + "" registered for name "" + name + """);
            }
        }
    }
}

通过以上的代码我们可以发现, 在得知是注册alias的步骤中, 这里也会有一个名字为aliasMap的map用来存储注册的别名,我这里有个疑惑, 就是怎么才能通过别名与原有的beanName进行映射呢? 如果都注册了, 那么将以哪个为准呢? 留给以后再看,留给评论。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/73652.html

相关文章

  • Spring IOC 容器源码分析系列文章导读

    摘要:本文是容器源码分析系列文章的第一篇文章,将会着重介绍的一些使用方法和特性,为后续的源码分析文章做铺垫。我们可以通过这两个别名获取到这个实例,比如下面的测试代码测试结果如下本小节,我们来了解一下这个特性。 1. 简介 Spring 是一个轻量级的企业级应用开发框架,于 2004 年由 Rod Johnson 发布了 1.0 版本。经过十几年的迭代,现在的 Spring 框架已经非常成熟了...

    NSFish 评论0 收藏0
  • 起来读Spring源码吧(容器初始化

    摘要:对于开发者来说,无疑是最常用也是最基础的框架之一。概念上的东西还是要提一嘴的用容器来管理。和是容器的两种表现形式。定义了简单容器的基本功能。抽象出一个资源类来表示资源调用了忽略指定接口的自动装配功能委托解析资源。 对于Java开发者来说,Spring无疑是最常用也是最基础的框架之一。(此处省略1w字吹Spring)。相信很多同行跟我一样,只是停留在会用的阶段,比如用@Component...

    libxd 评论0 收藏0
  • Spring源码容器基本实现2)

    摘要:进一步解析其他所有属性并统一封装至类型的实例中。是一个接口,在中存在三种实现以及。通过将配置文件中配置信息转换为容器的内部表示,并将这些注册到中。容器的就像是配置信息的内存数据库,主要是以的形式保存。而代码的作用就是实现此功能。 前言:继续前一章。 一、porfile 属性的使用 如果你使用过SpringBoot, 你一定会知道porfile配置所带来的方便, 通过配置开发环境还是生产...

    yagami 评论0 收藏0
  • 慕课网_《Spring入门篇》学习总结

    摘要:入门篇学习总结时间年月日星期三说明本文部分内容均来自慕课网。主要的功能是日志记录,性能统计,安全控制,事务处理,异常处理等等。 《Spring入门篇》学习总结 时间:2017年1月18日星期三说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com教学示例源码:https://github.com/zccodere/s...个人学习源码:https://git...

    Ververica 评论0 收藏0
  • Java深入-框架技巧

    摘要:从使用到原理学习线程池关于线程池的使用,及原理分析分析角度新颖面向切面编程的基本用法基于注解的实现在软件开发中,分散于应用中多出的功能被称为横切关注点如事务安全缓存等。 Java 程序媛手把手教你设计模式中的撩妹神技 -- 上篇 遇一人白首,择一城终老,是多么美好的人生境界,她和他历经风雨慢慢变老,回首走过的点点滴滴,依然清楚的记得当初爱情萌芽的模样…… Java 进阶面试问题列表 -...

    chengtao1633 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<