三、SpringIOC源码之XmlBeanFactory

SpringIOC源码之XmlBeanFactory

一、概述

1、说明

XmlBeanFactory是实现ioc方式之一,是那种比较屌丝的,功能对比ApplicationContext来讲差太多了。SpringIOC主要是如下三步骤

  • 定位:说白了就是找到我们传递进去的xml文件。
  • 加载:找到我们的xml文件位置后,将其解析成BeanDefinition对象。
  • 注册:将bean对象放到ioc的工厂里(其实就是个hashmap)。

二、源码

1、伪代码

//根据Xml配置文件创建Resource资源对象,属于定位
ClassPathResource resource = new ClassPathResource("beans.xml");
//创建DefaultListableBeanFactory工厂,是BeanFactory最核心的实现类
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
//创建XmlBeanDefinitionReader读取器,用于载入BeanDefinition。之所以需要BeanFactory作为参数,是因为会将读取的信息回调配置给factory
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
//XmlBeanDefinitionReader执行载入BeanDefinition的方法,最后会完成Bean的载入和注册。完成后Bean就成功的放置到IOC容器当中,以后我们就可以从中取得Bean来使用
reader.loadBeanDefinitions(resource);

2、源码

2.1、定位

ClassPathResource resource = new ClassPathResource("beans.xml");

// 定位
public ClassPathResource(String path) {
    this(path, (ClassLoader) null);
}

/**
 * path:beans.xml
 * classLoader:null
 */
public ClassPathResource(String path, ClassLoader classLoader) {
    Assert.notNull(path, "Path must not be null");
    String pathToUse = StringUtils.cleanPath(path);
    // 若path是以/开头,则去掉/
    if (pathToUse.startsWith("/")) {
        pathToUse = pathToUse.substring(1);
    }
    // 将path赋值给ClassPathResource的path变量
    this.path = pathToUse;
    this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
}

其实就是将资源文件路径传递给ClassPathResource的path变量

2.2、加载

2.2.1、创建工厂

DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

2.2.2、创建读取器

XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
/**
 * registry:DefaultListableBeanFactory
 */
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    // 将AbstractBeanDefinitionReader的registry赋值成DefaultListableBeanFactory
    this.registry = registry;

    // Determine ResourceLoader to use.
    if (this.registry instanceof ResourceLoader) {
        this.resourceLoader = (ResourceLoader) this.registry;
    }
    else {
        // 设置resourceLoader为PathMatchingResourcePatternResolver
        this.resourceLoader = new PathMatchingResourcePatternResolver();
    }

    // Inherit Environment if possible
    if (this.registry instanceof EnvironmentCapable) {
        this.environment = ((EnvironmentCapable)this.registry).getEnvironment();
    }
    else {
        this.environment = new StandardEnvironment();
    }
}

主要干了三件事

  • 将AbstractBeanDefinitionReader的registry设置为将AbstractBeanDefinitionReader的registry赋值成DefaultListableBeanFactory
  • resourceLoader = new PathMatchingResourcePatternResolver();
  • this.environment = new StandardEnvironment();

2.2.3、加载(核心)

reader.loadBeanDefinitions(resource);

// 啥也没干,就是给resource包了一层
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
    return loadBeanDefinitions(new EncodedResource(resource));
}

public EncodedResource(Resource resource) {
    this(resource, null);
}

public EncodedResource(Resource resource, String encoding) {
    Assert.notNull(resource, "Resource must not be null");
    this.resource = resource;
    this.encoding = encoding;
}
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
  try {
    // xml文件流
    InputStream inputStream = encodedResource.getResource().getInputStream();
    try {
      InputSource inputSource = new InputSource(inputStream);
      if (encodedResource.getEncoding() != null) {
        inputSource.setEncoding(encodedResource.getEncoding());
      }
      // do代表真正做事的方法
      return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
    }
    finally {
      inputStream.close();
    }
  }
}

根据beans.xml获取InputStream且传递给doLoadBeanDefinitions。

这里说下spring中do开头的都是真正做事的方法

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
      throws BeanDefinitionStoreException {
  try {
    // 根据resource获取Document对象
    Document doc = this.documentLoader.loadDocument(
        inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
    // 调用registerBeanDefinitions(doc, resource);
    return registerBeanDefinitions(doc, resource);
  }
}
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    // 创建BeanDefinitionDocumentReader对象
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    documentReader.setEnvironment(this.getEnvironment());
    // 获取容器中已注册的bean的数量,只是统计用,我们这不关心
    int countBefore = getRegistry().getBeanDefinitionCount();
    // 核心来了,继续看
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    return getRegistry().getBeanDefinitionCount() - countBefore;
}
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    this.readerContext = readerContext;
	// 获取根节点(beans标签这种根元素)
    Element root = doc.getDocumentElement();
    // do开头的都是真正做事的方法,我看到do就兴奋。
    doRegisterBeanDefinitions(root);
}
protected void doRegisterBeanDefinitions(Element root) {
  BeanDefinitionParserDelegate parent = this.delegate;
  // 委托模式
  this.delegate = createHelper(readerContext, root, parent);

  // 模板设计模式,空方法,开发者可自定义实现
  preProcessXml(root);
  // 核心方法,让代理类BeanDefinitionParserDelegate负责将xml里的bean装配到BeanDefinition对象
  parseBeanDefinitions(root, this.delegate);
  // 模板设计模式,空方法,开发者可自定义实现
  postProcessXml(root);

  this.delegate = parent;
}

protected BeanDefinitionParserDelegate createHelper(XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
    // 创建BeanDefinitionParserDelegate,委托类。委托模式
    BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext, environment);
    delegate.initDefaults(root, parentDelegate);
    return delegate;
}

public void initDefaults(Element root, BeanDefinitionParserDelegate parent) {
    // 设置默认节点属性,这个方法在BeanDefinitionParserDelegate类里,主要就是一些默认属性
    // 比如 default-lazy-init等
    populateDefaults(this.defaults, (parent != null ? parent.defaults : null), root);
    this.readerContext.fireDefaultsRegistered(this.defaults);
}
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);
      // 这里有个细节,就是instanceof Element了,比如xml中的换行也算一个元素的,也会多for一次,但是他不属于Element,所以不会进入逻辑
      if (node instanceof Element) {
        Element ele = (Element) node;
        if (delegate.isDefaultNamespace(ele)) {
          // 核心
          parseDefaultElement(ele, delegate);
        }
        else {
          delegate.parseCustomElement(ele);
        }
      }
    }
  }
  else {
    delegate.parseCustomElement(root);
  }
}
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
  // import
  if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
    // 负责解析import标签
    importBeanDefinitionResource(ele);
  }
  // alias  
  else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
    // 负责解析alias标签
    processAliasRegistration(ele);
  }
  // bean  
  else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
    // 负责解析bean标签,我这里主要分析这个  
    processBeanDefinition(ele, delegate);
  }
  // beans  
  else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
    // 递归算法。重新走遍解析bean的整个流程doRegisterBeanDefinitions
    doRegisterBeanDefinitions(ele);
  }
}
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
  BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
  if (bdHolder != null) {
    bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
    try {
      // Register the final decorated instance.
      BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
    }
  }
}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
    return parseBeanDefinitionElement(ele, null);
}

// 大致上就是获取bean标签的id和name和alias和class属性,
// 放到BeanDefinition,且将放到BeanDefinition放到BeanDefinitionHolder
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
  String id = ele.getAttribute(ID_ATTRIBUTE);
  String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
  String beanName = id;
  // 获取bean标签的class属性的value
  AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
  String[] aliasesArray = StringUtils.toStringArray(aliases);
  return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
  return null;
}

public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, BeanDefinition containingBean) {
    this.parseState.push(new BeanEntry(beanName));
    String className = null;
    // class属性
    if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
        className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
    }

    try {
        String parent = null;
        // parent
        if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
            parent = ele.getAttribute(PARENT_ATTRIBUTE);
        }
        // 创建BeanDefinition对象
        AbstractBeanDefinition bd = createBeanDefinition(className, parent);

        // 将lazy-init等属性装配到BeanDefinition对象中
        parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
        bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

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

// 创建BeanDefinition对象
public static AbstractBeanDefinition createBeanDefinition(
			String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException {
    GenericBeanDefinition bd = new GenericBeanDefinition();
    bd.setParentName(parentName);
    if (className != null) {
        // classLoader为null
        if (classLoader != null) {
            bd.setBeanClass(ClassUtils.forName(className, classLoader));
        }
        else {
            bd.setBeanClassName(className);
        }
    }
    return bd;
}

// 到这一步终于TMD返回了BeanDefinition对象,终于回到了起点方法processBeanDefinition(),那么下一步就是注册了。注册就简单太多了。

2.3、注册

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    // 加载的过程,我们已经在上面讲解了,这里返回了bean的定义,里面包含bean的全部信息
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        // 装饰者模式,这里不关心,用处不大。
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            // 重点是这个,负责注册bean
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
        }
        catch (BeanDefinitionStoreException ex) {
            getReaderContext().error("Failed to register bean definition with name '" +
                                     bdHolder.getBeanName() + "'", ele, ex);
        }
        // Send registration event.
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}
public static void registerBeanDefinition(
    BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
    throws BeanDefinitionStoreException {

  // 获取beanName,就是bean标签定义的id或name
  String beanName = definitionHolder.getBeanName();
  // 注册bean到ioc容器中
  registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

  // 获取别名
  String[] aliases = definitionHolder.getAliases();
  if (aliases != null) {
    for (String aliase : aliases) {
      // 将别名与beanName绑定
      registry.registerAlias(beanName, aliase);
    }
  }
}
// 简化版就是如下,就是直接往hashmap里扔了一下
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
    throws BeanDefinitionStoreException {

  synchronized (this.beanDefinitionMap) {
    this.beanDefinitionNames.add(beanName);
    this.frozenBeanDefinitionNames = null;
    // 放入ioc容器
    this.beanDefinitionMap.put(beanName, beanDefinition);
  }
}

3、小结

完结了,我在贴源码过程中删减了一些不必要的代码,只是贴了核心代码,可以发现我们只是将bean信息放到了ioc,并没有真正的实例化出来。实例化是DI的工作,IOC只是容器,DI后续文章会出。

三、总结

1.定义好Spring的配置文件

2.通过Resource对象将Spring配置文件进行抽象,抽象成一个Resource对象

3.定义好Bean工厂

4.定义好XmlBeanDefinitionReader对象,并将工厂作为参数传递进去供后续回调使用

5.通过XmlBeanDefinitionReader对象读取之前抽象出的Resource对象(包含了xml文件的解析过程)

6.本质上,xml文件的解析是由XmlBeanDefinitionReader对象交由BeanDefinitionParserDelegate委托完成的,实质上这里使用到了委托模式

7.解析完的xml文件信息都存放到BeanDefinition对象中,spring还采取了BeanDefinitionHolder来持有BeanDefinition对象的引用。

7.IOC容器创建完毕,用户可以通过容器获取到所需要的对象信息。(获取的时候其实就是DI依赖注入的过程,因为我们现在并没有实例化bean,只是将bean信息放到了ioc容器【map】中),key-》value 为 bean的name-》BeanDefinition

设计模式主要采取了工厂和委托。

四、建议

debug!debug!debug!按照我给的思路和流程和中文提示,自己写个helloworld去反复debug!

五、广告

QQ群:458430385
微信公众号
在这里插å¥å›¾ç‰‡æè¿°

发布了28 篇原创文章 · 获赞 33 · 访问量 8311

猜你喜欢

转载自blog.csdn.net/ctwctw/article/details/101804192