Spring原理学习系列之六:IOC原理之BeanDefinition注册

本文阅读 8 分钟

引言

在上一篇文章中,我们大致介绍了Bean创建、Bean加载的流程,但是由于文章篇幅所限,不能事无巨细的进行详细介绍。后续本系列的文章将对这部分的内容进行庖丁解牛,尽可能的将IOC中比较重要的细节说明清楚,以便于自己以及花时间阅读本文的读者可以加深对于Spring IOC的深入理解。

  • BeanDefinition
  • BeanDefinitionRegistry
  • 总结

一、BeanDefinition

纳尼,你还要说Spring IOC,之前的文章你还没有说够嘛? img 谁让Spring中关于IOC这部分的内容这么多呢,前面的文章还没有说的很细。所以只能继续慢慢往下唠叨了。废话不多说,我们来继续IOC。

BeanDefinition是用来描述Spring中的Bean,是包装Bean的数据结构。其源码如下所示:

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement { 

    
    //标准单例作用域的作用域标识符:“singleton”,对于扩展的bean工厂可能支持更多的作用域
    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

    //标准原型作用域的范围标识符:“prototype”
    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;


    //表示BeanDefinition是应用程序主要部分的角色提示,通常对应于用户定义的bean
    int ROLE_APPLICATION = 0;

    //表示BeanDefinition是某些大型配置的支持部分的角色提示,通常是一个外部ComponentDefinition。
    //当查看某个特定的ComponentDefinition时,认为bean非常重要,
    //以便在查看应用程序的整体配置时能够意识到这一点
    int ROLE_SUPPORT = 1;

    //角色提示表明一个BeanDefinition是提供一个完全背景的角色,并且与最终用户没有关系。
    //这个提示用于注册完全是ComponentDefinition内部工作的一部分的bean
    int ROLE_INFRASTRUCTURE = 2;

    //1、当前Bean父类名称
    //如果父类存在,设置这个bean定义的父定义的名称
    void setParentName(@Nullable String parentName);

    //如果父类存在,则返回当前Bean的父类的名称
    @Nullable
    String getParentName();

    //2、当前Bean的className
    //指定此bean定义的bean类名称。
    //类名称可以在bean factory后期处理中修改,通常用它的解析变体替换原来的类名称
    void setBeanClassName(@Nullable String beanClassName);

    //返回此bean定义的当前bean类名称
    //需要注意的是,这不一定是在运行时使用的实际类名,以防子类定义覆盖/继承其父类的类名
    //此外,这可能只是调用工厂方法的类,或者它 在调用方法的工厂bean引用的情况下甚至可能是空的
    //因此,不要认为这是在运行时定义的bean类型,而只是将其用于在单独的bean定义级别进行解析
    @Nullable
    String getBeanClassName();

    //3、bean作用域
    //覆盖此bean的目标范围,指定一个新的范围名称
    void setScope(@Nullable String scope);

    //返回此bean的当前目标作用域的名称,如果没有确定,返回null
    @Nullable
    String getScope();

    //懒加载
    //设置这个bean是否应该被延迟初始化。如果{false},那么这个bean将在启动时由bean工厂实例化,
    //这些工厂执行单例的立即初始化。
    //懒加载 <bean lazy-init="true/false">
    void setLazyInit(boolean lazyInit);

    //返回这个bean是否应该被延迟初始化,即不是在启动时立即实例化。只适用于单例bean。
    boolean isLazyInit();

    //5.依赖关系设置
    //设置这个bean依赖被初始化的bean的名字。 bean工厂将保证这些bean首先被初始化。
    //<bean depends-on="">
    void setDependsOn(@Nullable String... dependsOn);

    //返回这个bean依赖的bean名称
    @Nullable
    String[] getDependsOn();

    //6.是否是自动转配设置
    //设置这个bean是否是获得自动装配到其他bean的候选人。
    //需要注意是,此标志旨在仅影响基于类型的自动装配。
    //它不会影响按名称的显式引用,即使指定的bean没有标记为autowire候选,也可以解决这个问题。
    //因此,如果名称匹配,通过名称的自动装配将注入一个bean。
    void setAutowireCandidate(boolean autowireCandidate);

    //返回这个bean是否是自动装配到其他bean的候选者。就是是否在其他类中使用autowired来注入当前Bean的
    //是否为被自动装配 <bean autowire-candidate="true/false">
    boolean isAutowireCandidate();

    //7.主候选Bean
    //是否为主候选bean 使用注解:@Primary
    
    void setPrimary(boolean primary);
    
    //返回这个bean是否是主要的autowire候选者
    boolean isPrimary();

    //8.定义创建该Bean对象的工厂类
    //指定要使用的工厂bean(如果有的话), 这是调用指定的工厂方法的bean的名称
    void setFactoryBeanName(@Nullable String factoryBeanName);

    //如果有返回工厂bean的名字
    @Nullable
    String getFactoryBeanName();

    //9.创建该Bean对象的工厂方法
    //如果有,指定工厂方法。这个方法先将通过构造函数参数被调用,或者如果参数,将调用该方法的无参数构造
    void setFactoryMethodName(@Nullable String factoryMethodName);
    //如果存在,返回工厂方法名
    @Nullable
    String getFactoryMethodName();

    //10.返回此bean的构造函数参数值
    //返回此bean的构造函数参数值
    ConstructorArgumentValues getConstructorArgumentValues();

    default boolean hasConstructorArgumentValues() { 
        return !getConstructorArgumentValues().isEmpty();
    }

    //11.获取属性
    MutablePropertyValues getPropertyValues();

    default boolean hasPropertyValues() { 
        return !getPropertyValues().isEmpty();
    }

    //12.设置初始方法
    void setInitMethodName(@Nullable String initMethodName);

    @Nullable
    String getInitMethodName();


    void setDestroyMethodName(@Nullable String destroyMethodName);

    @Nullable
    String getDestroyMethodName();


    void setRole(int role);

    //13.当前Bean的角色
    //获取这个bean的角色
    int getRole();

    void setDescription(@Nullable String description);

    //14.可读描述
    //返回对bean定义的可读描述
    @Nullable
    String getDescription();

    //返回该bean定义来自的资源的描述
    @Nullable
    String getResourceDescription();

    //返回原始的BeanDefinition;如果没有,则返回null。允许检索装饰的bean定义
    @Nullable
    BeanDefinition getOriginatingBeanDefinition();
    
    //15.当前Bean的基本特性
    //是否是单例的
    boolean isSingleton();

    //是否是多例的
    boolean isPrototype();

    //是否是抽象类
    boolean isAbstract();

    

}

从上面的属性和方法分析可以看出,BeanDefinition对于一个Bean的描述做了比较完整的一套约束。这为后续的实现类提供了最基本的职责和属性。BeanDefinition只是一个接口,它的具体实现如下所示: img

二、BeanDefinitionRegistry

BeanDefinitionRegistry 继承了 AliasRegistry 接口,其核心子类有三个:SimpleBeanDefinitionRegistry、DefaultListableBeanFactory以及GenericApplicationContext,类机构图如下所示: img AliasRegistry 作为 BeanDefinitionRegistry 的顶层接口,它的作用主要为别名管理的通用型接口, AliasRegistry 定义了一些别名管理的方法。

public interface AliasRegistry { 

    
    void registerAlias(String name, String alias);

    
    void removeAlias(String alias);

    
    boolean isAlias(String name);


    String[] getAliases(String name);

}

BeanDefinitionRegistry 接口在实现AliasRegistry之外还定义了关于 BeanDefinition 注册、注销、查询等一系列的操作。

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);

}

我们可以看下BeanDefinitionRegistry的类实现结构如下所示:

img 这里关注下实现类GenericApplicationContext,其中比较重要的方法为registerBeanDefinition,它完成了BeanDefinition的注册 :

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry { 

    private final DefaultListableBeanFactory beanFactory;
    
    ...
    
    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException { 

        this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
    }
    ...
}

注册过程实际是通过DefaultListableBeanFactory的registerBeanDefinition来完成注册动作:

@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<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    if (this.manualSingletonNames.contains(beanName)) { 
                        Set<String> 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);
        }
    }

其实上面这么多代码最重要的就是:

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

this.beanDefinitionMap.put(beanName, beanDefinition);

三、总结

本文主要介绍了BeanDefinition以及BeanDefinition的注册,BeanDefinition是Spring处理Bean的统一的数据结构,BeanDefinitionRegistry的实现类对BeanDefinition完成了注册操作,注册最终结果保存在beanDefinitionMap这个ConcurrentHashMap中。今天的内容就到这里了,我们下次再会了哦。 img

本文为互联网自动采集或经作者授权后发布,本文观点不代表立场,若侵权下架请联系我们删帖处理!文章出自:https://blog.csdn.net/Diamond_Tao/article/details/103484170
-- 展开阅读全文 --
KillDefender 的 Beacon 对象文件 PoC 实现
« 上一篇 02-09
Web安全—逻辑越权漏洞(BAC)
下一篇 » 03-13

发表评论

成为第一个评论的人

热门文章

标签TAG

最近回复