Spring的BeanDefinitionReader

Spring的BeanDefinition的获取

类图

BeanDefinitionReader,从名字可以看出,它负责从某处获取BeanDefinition,某处是指定义的某个路径location,或者是更上一层的包装Resource。

public interface BeanDefinitionReader {

    //BeanDefinition的注册中心,一般都是BeanFactory
    //其实就是一个存放BeanDefinition的容器,实现中数据结构为Map<beanName, BeanDefinition>
    BeanDefinitionRegistry getRegistry();

    //获取ResourceLoader
    ResourceLoader getResourceLoader();

    //加载Bean的ClassLoader,如果为null,则意味着不加载Bean,仅仅注册BeanDefinition
    ClassLoader getBeanClassLoader();

    //如果一个Bean没有指定名字,则使用该名字生成器来生成名字
    BeanNameGenerator getBeanNameGenerator();

    //从resource从加载BeanDefinition,加载后放到BeanDefinitionRegistry中
    int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;
    //从多个从resource从加载BeanDefinition
    int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;

    //从指定的路径location中加载BeanDefinition,这个location可能是location pattern
    int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;
    //从指定的多个路径location中加载BeanDefinition
    int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;
}

AbstractBeanDefinitionReader

BeanDefinitionReader的抽象实现类,它的构造器很有意思。Environment是Spring3.1中引入的概念,所以,AbstractBeanDefinitionReader中的environment变量是此时加入的。

protected AbstracregistrytBeanDefinitionReader(BeanDefinitionRegistry registry) {
    //一般来说,这个registry就是实现了BeanDefinitionRegistry接口的Bean工厂
    this.registry = registry;

    //如果registry本身就实现了ResourceLoader,就使用registry作为resourceLoader
    if (this.registry instanceof ResourceLoader) {
        this.resourceLoader = (ResourceLoader) this.registry;
    }else {//否则,使用PathMatchingResourcePatternResolver作为resourceLoader
        this.resourceLoader = new PathMatchingResourcePatternResolver();
    }

    //如果registry本身实现了EnvironmentCapable,即它是有环境属性的,则使用registry作为它自身的environment
    if (this.registry instanceof EnvironmentCapable) {
        this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
    }
    else {//否则,使用StandardEnvironment作为environment
        this.environment = new StandardEnvironment();
    }
}

此外,它默认使用DefaultBeanNameGenerator作为Bean的名字生成器,具体的逻辑在BeanDefinitionReaderUtils中:

public static String generateBeanName(
            BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean)
            throws BeanDefinitionStoreException {
    //获取Bean的全类名,比如“com.maxwell.example.service.UserServiceImpl”
    String generatedBeanName = definition.getBeanClassName();
    //generatedBeanName为空,则看它是否有父BeanDefinition或者是不是FactoryBean
    if (generatedBeanName == null) {
        if (definition.getParentName() != null) {
            generatedBeanName = definition.getParentName() + "$child";
        }
        else if (definition.getFactoryBeanName() != null) {
            generatedBeanName = definition.getFactoryBeanName() + "$created";
        }
    }
    //如果此时,generatedBeanName仍然没有获取到,则抛异常
    if (!StringUtils.hasText(generatedBeanName)) {
        throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither " +
                "'class' nor 'parent' nor 'factory-bean' - can't generate bean name");
    }
    //此时,拿到了生成beanName的类名,比如“com.maxwell.example.service.UserServiceImpl”
    String id = generatedBeanName;
    if (isInnerBean) {
        // 如果是内部Bean,则在后面追加一个用哈希值生成的16进制的字符串
        id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition);
    }else {
        // 如果是Top-level的bean,则在后面追加一个序号,这个序号是从0开始的
        int counter = -1;
        while (counter == -1 || registry.containsBeanDefinition(id)) {
            counter++;
            id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + counter;
        }
    }
    //最后的bean名字,如“com.maxwell.example.service.UserServiceImpl#0”
    return id;
}

XmlBeanDefinitionReader

读取在Xml文件中定义的BeanDefinition,早期的Spring开发一般都会使用Xml文件来定义各种Bean。

PropertiesBeanDefinitionReader

读取在配置文件中定义的BeanDefinition,这种格式很少见,可参考Spring注释中该形式的示例。

按道理,所有可以去获取BeanDefinition的类都应该实现BeanDefinitionReader接口,但是在BeanDefinitionReader的注释中,有这样一段话:a bean definition reader不一定要实现该接口,该接口仅仅作为那些遵从标准命名约定的reader的建议。

Note that a bean definition reader does not have to implement this interface.

It only serves as suggestion for bean definition readers that want to follow standard naming conventions.

按照我的想法,既然有XmlBeanDefinitionReader去读取Xml中定义的BeanDefinition,有PropertiesBeanDefinitionReader去读取配置文件中定义的BeanDefiniton,就应该有类似ClassBeanDefinitionReader这种名字的reader去读取Class文件中通过注解定义的BeanDefiniton才对啊。很遗憾没有。TODO 为什么。

参考

What are inner beans in Spring?

Last updated