Resource接口

总体流程

  1. AbstractBeanDefinitionReader 通过 ResourceLoader 将资源文件路径转换成对应的 Resource 文件
  2. DocumentLoader 将 Resource 文件转换成 Document 文件
  3. 通过实现接口 BeanDefinitionDocumentReader 的 DefaultBeanDefinitionDocumentReader 类对 Document 进行解析,并使用 BeanDefinitionParserDelegate 对 Element 进行解析

ClassPathResource

作用:将文件路径处理成 Resource

测试代码

import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

import java.io.File;
import java.net.URL;

public class ClassPathResourceDemo {
    public static void main(String[] args) throws Exception {
        newClassPathResource();
        classLoaderTest();
    }

    public static void newClassPathResource() throws Exception {
        // 在 classpath 下准备任意一个文件, 可以是 xml/properties 等
        Resource resource = new ClassPathResource("person.properties");
        // 这里相当于将前面的 "/" 去掉
        File file = resource.getFile();
        String path = file.getAbsolutePath();
        System.out.println(path);
    }

    public static void classLoaderTest() {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        URL url = classLoader.getResource("");
        String protocol = url.getProtocol();
        String file = url.getFile();
        System.out.println("protocol = " + protocol);
        System.out.println("file = " + file);
    }

    public static void clazzTest() {
        // 这里必须使用 "/" 开头
        URL url2 = ClassPathResourceDemo.class.getResource("/person.properties");
        String url2Protocol = url2.getProtocol();
        String url2File = url2.getFile();
        System.out.println("url2Protocol = " + url2Protocol);
        System.out.println("url2File = " + url2File);
    }
}

ClassPathResource 源码解析

public class ClassPathResource extends AbstractFileResolvingResource {
    // 传入的文件路径: 会进行一个标准化处理
    private final String path;

    // 类加载器, 从getDefaultClassLoader()方法中可以看出其默认顺序:
    // 1. Thread.currentThread().getContextClassLoader()
    // 2. ClassUtils.class.getClassLoader()
    // 3. ClassLoader.getSystemClassLoader()
    @Nullable
    private ClassLoader classLoader;

    @Nullable
    private Class<?> clazz;

    public ClassPathResource(String path, @Nullable ClassLoader classLoader) {
        Assert.notNull(path, "Path must not be null");
        String pathToUse = StringUtils.cleanPath(path);
        // 使用"/person.properties"最终还是会被处理成"person.properties"
        if (pathToUse.startsWith("/")) {
            pathToUse = pathToUse.substring(1);
        }
        this.path = pathToUse;
        this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
    }
}

BeanDefinitionReader 接口

作用:加载上面处理好的 Resource 对象

// 读取资源文件并转换到 BeanDefinition
public interface BeanDefinitionReader {
    BeanDefinitionRegistry getRegistry();
    // ResourceLoader: 资源加载器, 根据给定的资源文件地址返回对应的 Resource
    ResourceLoader getResourceLoader();
    ClassLoader getBeanClassLoader();
    BeanNameGenerator getBeanNameGenerator();

    // 关键方法loadBeanDefinitions()
    int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;
    int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;
    int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;
    int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;
}

AbstractBeanDefinitionReader

public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader, EnvironmentCapable {

    protected final Log logger = LogFactory.getLog(getClass());

    // 用于注册 BeanDefinition
    // BeanDefinitionRegistry 约等于 BeanFactory
    // @Getter
    private final BeanDefinitionRegistry registry;

    // 加载资源对象
    // 缺省实现: PathMatchingResourcePatternResolver()
    // @Setter
    // @Getter
    @Nullable
    private ResourceLoader resourceLoader;

    // @Setter
    // @Getter
    @Nullable
    private ClassLoader beanClassLoader;

    // 用于读取环境相关的信息
    // 缺省实现: StandardEnvironment()
    // @Setter
    // @Getter
    private Environment environment;

    // 用于生成 Bean 的 name(id)
    // 缺省实现
    // @Setter(防止破坏默认值的设计)
    // @Getter
    private BeanNameGenerator beanNameGenerator = DefaultBeanNameGenerator.INSTANCE;


    protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        this.registry = registry;
        // 如果传入的 registry 同时实现了 ResourceLoader 接口, 那么 resourceLoader 设置为 registry
        // 如果传入的 registry 就是一个单纯的 BeanDefinitionRegistry 实现类对象, 那么 resourceLoader 设置为 PathMatchingResourcePatternResolver 对象
        if (this.registry instanceof ResourceLoader) {
            this.resourceLoader = (ResourceLoader) this.registry;
        }
        else {
            this.resourceLoader = new PathMatchingResourcePatternResolver();
        }
        // 动机同上, 缺省实现为 StandardEnvironment
        if (this.registry instanceof EnvironmentCapable) {
            this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
        }
        else {
            this.environment = new StandardEnvironment();
        }
    }

    @Override
    public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
        Assert.notNull(resources, "Resource array must not be null");
        int count = 0;
        for (Resource resource : resources) {
            // 具体加载单个 Resource 的方法由 XmlBeanDefinitionReader 等子类进行实现
            count += loadBeanDefinitions(resource);
        }
        return count;
    }


    public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
        ResourceLoader resourceLoader = getResourceLoader();
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException(
                    "Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
        }

        // 如果 ResourceLoader 是 ResourcePatternResolver 对象, 可以通过模式匹配批量加载 Source 对象
        if (resourceLoader instanceof ResourcePatternResolver) {
            // Resource pattern matching available.
            // 提供的是一个支持模式匹配的路径location, 可能对应多个Resource对象
            Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
            int count = loadBeanDefinitions(resources);
            if (actualResources != null) {
                Collections.addAll(actualResources, resources);
            }
            return count;
        }
        else {
            // Can only load single resources by absolute URL.
            // 一般的 ResourceLoader 只能通过绝对路径来加载单个 Source
            Resource resource = resourceLoader.getResource(location);
            int count = loadBeanDefinitions(resource);
            if (actualResources != null) {
                // 将 Resource 对象添加到 actualResources 集合中
                actualResources.add(resource);
            }
            return count;
        }
    }
}

XmlBeanDefinitionReader

loadBeanDefinitions 方法

  • 通过 Resource 对象加载,即 loadBeanDefinitions(Resource resource) 由子类(XmlBeanDefinitionReader等)实现
  • 通过 String 路径加载,即 loadBeanDefinitions(String location, Set<Resource> actualResources)
    1. 如果 ResourceLoader 是 ResourcePatternResolver,那么支持 location 中使用模式匹配,可以解析 location,批量导入多个 Resource
    2. 如果 ResourceLoader 不是 ResourcePatternResolver,那么 location 只能使用绝对路径
    3. 解析出来的 Resource 对象都会被添加到传入的(形参) Set 集合(actualResources)中
    4. 通过 String 路径加载最后还是落实到通过 Resource 方式加载上
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
    return loadBeanDefinitions(new EncodedResource(resource));
}

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
    // 当前正在被加载的 Resources
    Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();

    // 检查是否重复加载, 什么情况下会出现这种情况?
    if (!currentResources.add(encodedResource)) {
        throw e;
    }

    try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
        // 从encodedResource中获取InuptStream, 封装成InputStore
        InputSource inputSource = new InputSource(inputStream);
        if (encodedResource.getEncoding() != null) {
            inputSource.setEncoding(encodedResource.getEncoding());
        }
        // 真正的处理操作doLoadBeanDefinitions()
        return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
    }
    catch (IOException ex) {
        throw e;
    }
    finally {
        // resource处理完成, 从集合中删除
        currentResources.remove(encodedResource);
        if (currentResources.isEmpty()) {
            this.resourcesCurrentlyBeingLoaded.remove();
        }
    }
}

getEntityResolver 方法

主要考虑在没有设置 EntityResolver 的情况下,根据 ResourceLoader 有两种可能:

  1. 如果 ResourceLoader 为 null,那么 new DelegatingEntityResolver(getBeanClassLoader())
  2. 如果 ResourceLoader 不为 null,那么 new ResourceEntityResolver(resourceLoader)
// 自定义处理外部实体时, 需要向SAX驱动器注册一个EntityResolver
// EntityResolver的作用是由项目本身来提供一个如何寻找DTD声明的方法
protected EntityResolver getEntityResolver() {
    if (this.entityResolver == null) {
        // Determine default EntityResolver to use.
        // 如果没有设置EntityResolver
        ResourceLoader resourceLoader = getResourceLoader();
        if (resourceLoader != null) {
            this.entityResolver = new ResourceEntityResolver(resourceLoader);
        }
        else {
            this.entityResolver = new DelegatingEntityResolver(getBeanClassLoader());
        }
    }
    return this.entityResolver;
}

doLoadBeanDefinitions 方法

loadBeanDefinitions(Source source) 被包装成 loadBeanDefinitions(EncodedSource source),再进一步实际处理的是 doLoadBeanDefinitions(..) 方法,其中 InputStore 是从 Source 中获取的 InputStream 的一层包装。

doLoadBeanDefinition() 方法的步骤:

  1. doLoadDocument(inputSource, resource):将 Resource 转变为 Document,通过调用 documentLoader.loadDocument(..) 方法
  2. registerBeanDefinitions(doc, resource):解析 Document 并转化成 BeanDefinition 进行注册
// 核心方法
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
    // Resource -> Document
    Document doc = doLoadDocument(inputSource, resource);
    int count = registerBeanDefinitions(doc, resource);
    return count;
}

registerBeanDefinitions 方法

  1. 创建一个 BeanDefinitionDocumentReader,默认是 DefaultBeanDefinitionDocumentReader 对象,由 private Class documentReaderClass 字段的默认值 DefaultBeanDefinitionDocumentReader.class 决定
  2. 通过该 BeanDefinitionDocumentReader 对象的 registerBeanDefinitions(Document doc, XmlReaderContext readerContext) 方法来进行注入 BeanDefinition
// 核心方法
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    // 创建一个 BeanDefinitionDocumentReader, 默认是DefaultBeanDefinitionDocumentReader对象, 由 private Class<? extends BeanDefinitionDocumentReader> documentReaderClass = DefaultBeanDefinitionDocumentReader.class;决定
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();

    // 获取注入前BeanFactory中BeanDefinition的数量
    int countBefore = getRegistry().getBeanDefinitionCount();

    // 调用documentReader中的方法完成
    // 对resource再一次进行封装成XmlReaderContext
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));

    // 获取注入后BeanFactory中BeanDefinition的数量
    // 二者相减, 返回当前注入BeanFactory中BeanDefinition的数量
    return getRegistry().getBeanDefinitionCount() - countBefore;
}

DefaultBeanDefinitionDocumentReader

doRegisterBeanDefinitions 方法

registerBeanDefinitions(..) 方法获取到 Document 的 root 节点后,调用 doRegisterBeanDefinitions(Element root) 方法进行真正的工作。

在 doRegisterBeanDefinitions 方法中:

  1. createDelegate(..) 创建 BeanDefinitionParserDelegate 对象,对 ReaderContext 的包装(似乎还是对 Resource、Document 的包装)?或者含有什么方便的解析工具?
  2. 处理了 <beans> 标签中的 profile 属性,(如果没有 profile 属性,则不进行额外处理)。处理完成后,调用 parseBeanDefinitions(root, this.delegate) 进行根节点的解析
  3. 调用 parseBeanDefinitions(..) 方法
  4. 疑问:BeanDefinitionParserDelegate parent = this.delegate;this.delegate = parent; 是为什么?
protected BeanDefinitionParserDelegate createDelegate(XmlReaderContext readerContext, Element root, @Nullable BeanDefinitionParserDelegate parentDelegate) {
    BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
    delegate.initDefaults(root, parentDelegate);
    return delegate;
}

@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    // 为readerContext进行赋值, 本质上是一个Source的包装
    this.readerContext = readerContext;
    // 对doc的根节点进行解析 (Spring配置文件的根节点: beans)
    doRegisterBeanDefinitions(doc.getDocumentElement());
}

// 核心方法
protected void doRegisterBeanDefinitions(Element root) {
    BeanDefinitionParserDelegate parent = this.delegate;
    this.delegate = createDelegate(getReaderContext(), root, parent);

    if (this.delegate.isDefaultNamespace(root)) {
        // 获取<beans>根节点中的profile属性
        String profileSpec = root.getAttribute("profile");
        if (StringUtils.hasText(profileSpec)) {
            String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                return;
            }
        }
    }

    // preProcessXml(root) 和 postProcessXml(root) 这两个方法都是空实现, 什么都没有做
    //preProcessXml(root);
    parseBeanDefinitions(root, this.delegate);
    //postProcessXml(root);

    // 还原回去, 这是为什么?
    this.delegate = parent;
}

parseDefaultElement 方法

parseBeanDefinitions(..) 方法是常规的 XML 解析技术,获取根节点 root 的非空白子元素,即获取 <beans> 标签的 <bean>

通过调用 parseDefaultElement(ele, delegate) 来解析 <beans> 的子标签,包括 <import><alias><bean> 以及嵌套的 <beans>,针对前三种子标签,有对应专门的解析方法,对于嵌套的 <beans> 则采用递归处理。

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    // 默认情况
    if (delegate.isDefaultNamespace(root)) {
        NodeList nl = root.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            if (node instanceof Element) {
                // 上面都是常规的XML解析, 如果root对应<beans>标签, 那么ele就是一个<bean>标签
                Element ele = (Element) node;
                // TODO: XML解析技术中的Namespace需要再了解下, 应该是schema
                if (delegate.isDefaultNamespace(ele)) {
                    parseDefaultElement(ele, delegate);
                }
                else {
                    delegate.parseCustomElement(ele);
                }
            }
        }
    }
    else {
        // 自定义元素? 怎么解释?
        // 例如 <tx:annotation> 这些标签
        delegate.parseCustomElement(root);
    }
}

// 核心方法: 解析单个bean标签
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    if (delegate.nodeNameEquals(ele, "import")) {
        importBeanDefinitionResource(ele);
    }
    else if (delegate.nodeNameEquals(ele, "alias")) {
        processAliasRegistration(ele);
    }
    else if (delegate.nodeNameEquals(ele, "bean")) {
        processBeanDefinition(ele, delegate);
    }
    else if (delegate.nodeNameEquals(ele, "beans")) {
        // recurse
        // 递归调用
        doRegisterBeanDefinitions(ele);
    }
}

importBeanDefinitionResource 方法

protected void importBeanDefinitionResource(Element ele) {
    String location = ele.getAttribute("resource");
    if (!StringUtils.hasText(location)) {
        getReaderContext().error("Resource location must not be empty", ele);
        return;
    }

    // Resolve system properties: e.g. "${user.dir}"
    location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);

    Set<Resource> actualResources = new LinkedHashSet<>(4);

    // Discover whether the location is an absolute or relative URI
    boolean absoluteLocation = false;
    absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();

    // Absolute or relative?
    if (absoluteLocation) {
        int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
    } else {
        // No URL -> considering resource location as relative to the current file.
        int importCount;
        Resource relativeResource = getReaderContext().getResource().createRelative(location);
        if (relativeResource.exists()) {
            importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
            actualResources.add(relativeResource);
        } else {
            String baseLocation = getReaderContext().getResource().getURL().toString();
            importCount = getReaderContext().getReader().loadBeanDefinitions(
                StringUtils.applyRelativePath(baseLocation, location), actualResources);
        }
    }
    Resource[] actResArray = actualResources.toArray(new Resource[0]);
    getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
}

processAliasRegistration 方法

protected void processAliasRegistration(Element ele) {
    String name = ele.getAttribute("name");
    String alias = ele.getAttribute("alias");
    boolean valid = true;
    if (!StringUtils.hasText(name)) {
        getReaderContext().error("Name must not be empty", ele);
        valid = false;
    }
    if (!StringUtils.hasText(alias)) {
        getReaderContext().error("Alias must not be empty", ele);
        valid = false;
    }
    if (valid) {
        getReaderContext().getRegistry().registerAlias(name, alias);
        getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));
    }
}

processBeanDefinition 方法

  1. <bean> 标签的解析
  2. holder 的注册
  3. 利用事件机制通知监听器
// 处理bean标签
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    // 1. 委托delegate对象来解析bean标签, 返回一个holder, holder中包含bean标签中的各种属性: class/name/id/alias等
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        // 2. 如果bean标签下面还有自定义属性、标签, 还需要再次对自定义的标签进行解析
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        // 3. 对解析完成后的holder进行注册, 委托给BeanDefinitionReaderUtils
        BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
        // 4. 发出事件, 通知相关的监听器EventListener
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}

BeanDefinitionParserDelegate

parseBeanDefinitionElement 方法(解析Bean标签)

  1. name 属性可以通过指定的分隔符来指定多个字段,这些字段都会被作为 alias

  2. id 属性作为 beanName 的默认值。

    但如果没有设置 id 属性,同时设置了 name 属性,就会将第一个 name 作为 beanName

  3. 检查是否有重复的 beanName

  4. 通过 parseBeanDefinitionElement 去进一步解析 bean 标签

  5. 考虑在 id 属性和 name 属性都没有设置的情况下,生成 beanName

    1. 如果 containingBean != null,通过 BeanDefinitionReaderUtils.generateBeanName() 来生成 beanName
    2. 如果 containingBean == null,通过 readerContext.generateBeanName() 来生成 beanName
  6. 通过 beanName、aliases、BeanDefinition 来创建一个 BeanDefinitionHolder。

    换句话说,这是否意味着 BeanDefinition 中 beanName 是可以为 null 的,而 BeanDefinitionHolder 中 beanName 必须不为 null ?也许不是,但 BeanDefinition 中不包含 aliases

@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
    String id = ele.getAttribute("id");
    String nameAttr = ele.getAttribute("name");

    // 1. name 属性可以通过指定的分隔符来指定多个字段,这些字段都会被作为 alias
    List<String> aliases = new ArrayList<>();
    if (StringUtils.hasLength(nameAttr)) {
        // 根据StringTokenizer进行分词, 去除首尾空格和空元素, 例如, "a,,b"只会保留a和b
        String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; ");
        aliases.addAll(Arrays.asList(nameArr));
    }

    // 2. id 属性作为 beanName 的默认值
    String beanName = id;
    if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
        // 如果id属性为null, 并且name属性不为null, 就会将第一个name作为beanName
        beanName = aliases.remove(0);
    }

    if (containingBean == null) {
        // 3. 检查是否有重复的beanName
        checkNameUniqueness(beanName, aliases, ele);
    }

    // 4. 得到BeanDefinition
    AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    if (beanDefinition != null) {
        // 正常的BeanDefinition处理流程
        if (!StringUtils.hasText(beanName)) {
            // 5. id属性和name属性都没有设置的情况下, beanName为null
            if (containingBean != null) {
                // containingBean什么情况下不为null呢?
                beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
            } else {
                beanName = this.readerContext.generateBeanName(beanDefinition);
                String beanClassName = beanDefinition.getBeanClassName();
                if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                    !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                    aliases.add(beanClassName);
                }
            }
        }
        String[] aliasesArray = StringUtils.toStringArray(aliases);
        //
        return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    }

    // 解析出来是个不正常的Beandefinition(null), 直接返回null
    return null;
}

parseBeanDefinitionElement 方法(重载、重点)

  1. 解析 class 和 parent 属性
  2. 通过 className(class属性值) 和 parent 来创建 BeanDefinition
  3. 各种真正的解析逻辑
    1. parseBeanDefinitionAttributes:设置 BeanDefinition 的各个属性值,没有设置的使用默认值
    2. parseMetaElements:
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {

    this.parseState.push(new BeanEntry(beanName));

    // 1. 解析class属性和parent属性
    String className = null;
    if (ele.hasAttribute("class")) {
        className = ele.getAttribute("class").trim();
    }
    String parent = null;
    if (ele.hasAttribute("parent")) {
        parent = ele.getAttribute("parent");
    }

    try {
        // 2. 通过 className(class属性值) 和 parent 来创建 BeanDefinition
        AbstractBeanDefinition bd = createBeanDefinition(className, parent);

        // 3. 各种解析逻辑
        // 3.1 设置属性值
        parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
        bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

        // 3.2 
        parseMetaElements(ele, bd);
        parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
        parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

        parseConstructorArgElements(ele, bd);
        parsePropertyElements(ele, bd);
        parseQualifierElements(ele, bd);

        bd.setResource(this.readerContext.getResource());
        bd.setSource(extractSource(ele));

        return bd;
    }
    finally {
        this.parseState.pop();
    }

    return null;
}

parseBeanDefinitionAttributes 方法(设置 BeanDefinition 属性)

  1. singleton 属性被 scope 属性取代,不能在 bean 标签中使用 singleton 属性
  2. 如果当前 bean 未定义 scope 属性, 但是内部的 bean 定义了 scope 属性, 那么使用内部 bean 的 scope 属性
  3. 设置 abstract 属性,默认值为 false
  4. 设置 lazy-init 属性
  5. 设置 autowire 属性,自动注入方式:
    • AbstractBeanDefinition.AUTOWIRE_NO
    • AbstractBeanDefinition.AUTOWIRE_BY_NAME
    • AbstractBeanDefinition.AUTOWIRE_BY_TYPE
    • AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR
    • AbstractBeanDefinition.AUTOWIRE_AUTODETECT
  6. 设置 depends-on 属性,可以设置多个,使用分隔符分隔即可
  7. 设置 autowire-candidate 属性
  8. 设置 primary 属性
  9. 设置 init-method 属性
  10. 设置 destroy-method 属性
  11. 设置 factory-method 属性
  12. 设置 factory-bean 属性
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
                                                            @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {

    // 1. 检查 scope 属性
    if (ele.hasAttribute("singleton")) {
        error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
    }
    else if (ele.hasAttribute("scope")) {
        bd.setScope(ele.getAttribute("scope"));
    }
    else if (containingBean != null) {
        // 2. 如果当前 bean 未定义 scope 属性, 但是内部的 bean 定义了 scope 属性, 那么使用内部 bean 的 scope 属性
        bd.setScope(containingBean.getScope());
    }

    // 3. 如果 abstract 属性设置为 true, 进行设置
    if (ele.hasAttribute("abstract")) {
        bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute("abstract")));
    }

    // 4. 设置lazy-init
    String lazyInit = ele.getAttribute("lazy-init");
    if (isDefaultValue(lazyInit)) {
        lazyInit = this.defaults.getLazyInit();
    }
    bd.setLazyInit(TRUE_VALUE.equals(lazyInit));

    // 5. 设置autowire
    String autowire = ele.getAttribute("autowire");
    bd.setAutowireMode(getAutowireMode(autowire));

    // 6. 设置depends-on
    if (ele.hasAttribute("depends-on")) {
        String dependsOn = ele.getAttribute("depends-on");
        bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, ",; "));
    }

    // 7. 设置autowire-candidate
    String autowireCandidate = ele.getAttribute("autowire-candidate");
    if (isDefaultValue(autowireCandidate)) {
        String candidatePattern = this.defaults.getAutowireCandidates();
        // TODO: 为什么获取到默认值后还判断是否为null呢?
        if (candidatePattern != null) {
            String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
            bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
        }
    } else {
        bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
    }

    // 8. 设置primary
    if (ele.hasAttribute("primary")) {
        bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute("primary")));
    }

    // 9. 设置init-method 或默认的init-method
    if (ele.hasAttribute("init-method")) {
        String initMethodName = ele.getAttribute("init-method");
        bd.setInitMethodName(initMethodName);
    } else if (this.defaults.getInitMethod() != null) {
        bd.setInitMethodName(this.defaults.getInitMethod());
        bd.setEnforceInitMethod(false);
    }

    // 10. 设置destroy-method 或默认destroy-method
    if (ele.hasAttribute("destroy-method")) {
        String destroyMethodName = ele.getAttribute("destroy-method");
        bd.setDestroyMethodName(destroyMethodName);
    } else if (this.defaults.getDestroyMethod() != null) {
        bd.setDestroyMethodName(this.defaults.getDestroyMethod());
        bd.setEnforceDestroyMethod(false);
    }

    // 11. 设置factory-method
    if (ele.hasAttribute("factory-method")) {
        bd.setFactoryMethodName(ele.getAttribute("factory-method"));
    }

    // 12. 设置factory-bean
    if (ele.hasAttribute("factory-bean")) {
        bd.setFactoryBeanName(ele.getAttribute("factory-bean"));
    }

    return bd;
}

parseMetaElements 方法(解析 bean 标签的 meta 子标签)

public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
    // 获取bean标签下的子标签
    NodeList nl = ele.getChildNodes();
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        // 解析<bean>标签下面的<meta>标签
        if (isCandidateElement(node) && nodeNameEquals(node, "meta")) {
            Element metaElement = (Element) node;
            String key = metaElement.getAttribute("key");
            String value = metaElement.getAttribute("value");
            BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
            attribute.setSource(extractSource(metaElement));
            // attributeAccessor 就是一个 BeanDefinition, AbstractBeanDefinition 继承于 BeanMetadataAttributeAccessor
            // 但 BeanDefinition 是一个接口, 且和该父类没有关系, 似乎是一种设计模式, 适配器? 忘了!
            attributeAccessor.addMetadataAttribute(attribute);
        }
    }
}

parseLookupOverrideSubElements 方法

TODO

parseReplacedMethodSubElements 方法

TODO

parseConstructorArgElements 方法

public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
    NodeList nl = beanEle.getChildNodes();
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        if (isCandidateElement(node) && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) {
            parseConstructorArgElement((Element) node, bd);
        }
    }
}

// 具体细节
public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
    String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
    String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
    if (StringUtils.hasLength(indexAttr)) {
        try {
            int index = Integer.parseInt(indexAttr);
            if (index < 0) {
                error("'index' cannot be lower than 0", ele);
            }
            else {
                try {
                    this.parseState.push(new ConstructorArgumentEntry(index));
                    Object value = parsePropertyValue(ele, bd, null);
                    ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
                    if (StringUtils.hasLength(typeAttr)) {
                        valueHolder.setType(typeAttr);
                    }
                    if (StringUtils.hasLength(nameAttr)) {
                        valueHolder.setName(nameAttr);
                    }
                    valueHolder.setSource(extractSource(ele));
                    if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
                        error("Ambiguous constructor-arg entries for index " + index, ele);
                    }
                    else {
                        bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
                    }
                }
                finally {
                    this.parseState.pop();
                }
            }
        }
    }
    else {
        try {
            this.parseState.push(new ConstructorArgumentEntry());
            Object value = parsePropertyValue(ele, bd, null);
            ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
            if (StringUtils.hasLength(typeAttr)) {
                valueHolder.setType(typeAttr);
            }
            if (StringUtils.hasLength(nameAttr)) {
                valueHolder.setName(nameAttr);
            }
            valueHolder.setSource(extractSource(ele));
            bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
        }
        finally {
            this.parseState.pop();
        }
    }
}

parsePropertyElements 方法(复杂 TODO)

public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
    NodeList nl = beanEle.getChildNodes();
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
            parsePropertyElement((Element) node, bd);
        }
    }
}

public void parsePropertyElement(Element ele, BeanDefinition bd) {
    String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
    if (!StringUtils.hasLength(propertyName)) {
        error("Tag 'property' must have a 'name' attribute", ele);
        return;
    }
    this.parseState.push(new PropertyEntry(propertyName));
    try {
        if (bd.getPropertyValues().contains(propertyName)) {
            error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
            return;
        }
        Object val = parsePropertyValue(ele, bd, propertyName);
        PropertyValue pv = new PropertyValue(propertyName, val);
        parseMetaElements(ele, pv);
        pv.setSource(extractSource(ele));
        bd.getPropertyValues().addPropertyValue(pv);
    }
    finally {
        this.parseState.pop();
    }
}

parseQualifierElements 方法

public void parseQualifierElements(Element beanEle, AbstractBeanDefinition bd) {
    NodeList nl = beanEle.getChildNodes();
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ELEMENT)) {
            parseQualifierElement((Element) node, bd);
        }
    }
}

   转载规则


《Resource接口》 熊水斌 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
数仓 数仓
数仓项目项目准备技术选型 系统数据流程图 版本选型 集群资源规划 用户行为日志用户行为日志概述用户行为日志的内容,主要包含用户的各项行为信息以及行为所处的环境信息。收集这些信息的主要目的是为了优化产品和为各项分析统计指标提供数据支撑。
2023-03-16
下一篇 
BeanFactory接口与ApplicationContext接口功能介绍 BeanFactory接口与ApplicationContext接口功能介绍
类关系结构 BeanFactory 功能介绍BeanFactory 是核心容器,负责管理 Bean 对象 BeanFactory 接口的功能只有一个 getBean() 方法 BeanFactory 的实现类(DefaultListab
2023-03-16
  目录