首页 > 编程笔记 > Java笔记

访问者模式在Spring源码中的应用

本节介绍访问者模式在 Spring 中的应用。

在 Spring IoC 中,BeanDefinition 用来存储 Spring Bean 的定义信息,比如属性值、构造方法参数或者更具体的实现。Spring 解析完配置后,会生成 BeanDefinition 并且记录下来。下次 getBean 获取 Bean 时,会通过 BeanDefinition 来实例化具体的 Bean 对象。

BeanDefinition 是一个接口,即一个抽象的定义,实际使用的是其实现类,如 ChildBeanDefinition、RootBeanDefinition、GenericBeanDefinition 等。

Spring 中的 BeanDefinitionVisitor 类主要用于访问 BeanDefinition,解析属性或者构造方法里面的占位符,并把解析结果更新到 BeanDefinition 中。这里应用的就是访问者模式。抽象元素为 BeanDefinition,具体元素有 RootBeanDefinition、ChildBeanDefinition、GenericBeanDefinition 等。

因为没有对访问者进行扩展,所以这里只有一个具体访问者 BeanDefinitionVisitor,没有再抽出一层抽象访问者。

BeanDefinitionVisitor 类的源码如下。 
public class BeanDefinitionVisitor {
    @Nullable
    private StringValueResolver valueResolver;

    public BeanDefinitionVisitor(StringValueResolver valueResolver) {
        Assert.notNull(valueResolver, "StringValueResolver must not be null");
        this.valueResolver = valueResolver;
    }

    protected BeanDefinitionVisitor() {
    }

    public void visitBeanDefinition(BeanDefinition beanDefinition) {
        visitParentName(beanDefinition);
        visitBeanClassName(beanDefinition);
        visitFactoryBeanName(beanDefinition);
        visitFactoryMethodName(beanDefinition);
        visitScope(beanDefinition);         
        if (beanDefinition.hasPropertyValues()) {
             visitPropertyValues(beanDefinition.getPropertyValues());
        }
        if (beanDefinition.hasConstructorArgumentValues()) {
            ConstructorArgumentValues cas = beanDefinition.getConstructorArgumentValues();
            visitIndexedArgumentValues(cas.getIndexedArgumentValues());
            visitGenericArgumentValues(cas.getGenericArgumentValues());
        }
    }
    protected void visitParentName(BeanDefinition beanDefinition) {
        String parentName = beanDefinition.getParentName();
        if (parentName != null) {
            String resolvedName = resolveStringValue(parentName);
            if (!parentName.equals(resolvedName)) {
                beanDefinition.setParentName(resolvedName);
            }
        }
    }
    ...
} 
以上没有使用双重分派模式,直接调用 visit 进行元素的访问。visitBeanDefinition() 方法分别实现了不同的 visit 来对相同的数据进行不同的处理。我们看到,在 visitBeanDefinition() 方法中,访问了其它数据,比如父类的名字、自己的类名、在 IoC 容器中的名称等各种信息。

所有教程

优秀文章