栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring源码分析(1) —— 从Xml的加载到解析

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring源码分析(1) —— 从Xml的加载到解析

题外话:

接口&多态

我有一辆自行车,每天骑着它去上班

package com.zhao.SpringIoc;

public class Bike {
    public void go() {
        System.out.println("骑单车去上班");
    }
}

package com.zhao.SpringIoc;


public class ShuaiQiZhao {

    private static Bike bike;

    // private static Bus bus;

    // private static Car car;

    public static void main(String[] args) {
        bike = new Bike();
        bike.go();  // 骑单车去上班
    }
}

过了不久,我不想骑车觉得太累,于是我坐公交上班

package com.zhao.SpringIoc;

public class Bus {
    public void go() {
        System.out.println("乘坐公交去上班");
    }
}
package com.zhao.SpringIoc;


public class ShuaiQiZhao {
    
    // private static Bike bike;
    
     private static Bus bus;
     
    // private static Car car;

    public static void main(String[] args) {
        bus = new Bus();
        bus.go();  // 乘坐公交去上班
    }
}

没过多久我有钱了,买了一辆汽车,于是我每天开车上班

package com.zhao.SpringIoc;

public class Car {
    public void go() {
        System.out.println("开着玛莎去上班");
    }
}
package com.zhao.SpringIoc;


public class ShuaiQiZhao {

    // private static Bike bike;

    // private static Bus bus;

    private static Car car;

    public static void main(String[] args) {
        car = new Car();
        car.go();  // 开着玛莎去上班
    }
}

当我每买一辆交通工具,我就要修改Person类中成员变量和main方法中的交通工具。有人觉得这也没什么呀?那是因为代码不是你写的,看当然比做要来的舒服!而且如果有一千种交通工具,你还会这样说吗?

用多态改善上述情况

管家管理这些交通工具

package com.zhao.SpringIoc;

public interface Movable {

    public void go();   // 抽象三种交通工具共有行为(去上班)

}

三种交通工具实现这个接口

package com.zhao.SpringIoc.Impl;

import com.zhao.SpringIoc.Movable;

public class Bike implements Movable {
    
    public void go() {
        System.out.println("骑单车去上班");
    }
    
}
package com.zhao.SpringIoc.Impl;

import com.zhao.SpringIoc.Movable;

public class Bus implements Movable {

    public void go() {
        System.out.println("乘坐公交去上班");
    }

}
package com.zhao.SpringIoc.Impl;

import com.zhao.SpringIoc.Movable;

public class Car implements Movable {

    public void go() {
        System.out.println("开着玛莎去上班");
    }

}

帅气赵找到管家

package com.zhao.SpringIoc;

import com.zhao.SpringIoc.Impl.Car;


public class ShuaiQiZhao {

    private static Movable movable;

    public static void main(String[] args) {
        movable = new Car();
        movable.go();  // 开着玛莎去上班
    }
}

对比一下,以前想用某种交通工具就要声明它的成员变量,修改main方法的类名,引用名。

现在只需要改下类名就行,是不是很方便?

但这也不是最方便的,就是每次都有自己 new 对象。但这也是无可奈何的,那就真的没有别的办法了吗?

Spring最擅长的就是管理,需要什么对象你管它要就行。传统编程,需要手动创建各种对象,在对象内部控制对象。Spring则是将设计好的对象交给容器管理(IOC)。需要什么对象,你找它拿。


正文

Spring的对象是由Xml文档,或者注解产生的。我们先不说注解,那离我们太远。就从xml开始谈。

搭建环境

接口:BookService

package com.zhao.Interface;

public interface BookService {
    
    double getBookPrice();
}

接口:PressService

package com.zhao.Interface;

public interface PressService {
    
    String say();
}

 接口实现类:BookServiceImpl

package com.zhao.service;

import com.zhao.Interface.BookService;


public class BookServiceImpl implements BookService {

    @Override
    public double getBookPrice() {
        return 508.8;
    }
}

接口实现类:PressServiceImpl

package com.zhao.service;

import com.zhao.Interface.BookService;
import com.zhao.Interface.PressService;

public class PressServiceImpl implements PressService {
    
    private BookService bookService;

    
    public void setBookService(BookService bookService) {
        this.bookService = bookService;
    }

    @Override
    public String say() {
        return "本书的价格是:" + bookService.getBookPrice();
    }
}

配置文件:applicationContext.xml




    
    
    

    
    
        
        
    

启动类:SourceCodeLearning

package com.zhao;

import com.zhao.Interface.PressService;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;


public class SourceCodeLearning {

    public static void main(String[] args) {

        //从容器中获取名字为user的bean
        BeanFactory bf = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
        PressService pressService = (PressService) bf.getBean("pressService");

        //调用bean的方法
        String price = pressService.say();
        System.out.println(price);

    }
}

好了,开始了哦!

咱们由结果分析过程,现在你把自己当成Spring,首先第一件事要做的是什么?是不是加载配置文件,看看有哪些Bean需要创建?万事开头难,迈出了第一步下面就好办了!

  1. 加载配置文件
  2. 解析配置文件
  3. 解析后的Bean信息放入Map集合中

加载配置文件

我现在是Spring,我并不知道我接下来面临的是什么,是加载Xml文件,还是加载JSON文件,亦或加载yaml文件,这些对于我都是未知的。但是我一点也不慌,你们每一种配置文件都要实现我的规则,也就是 Resource,现在是Xml文件,用来加载Xml文件的是 XmlBeanFactory

package org.springframework.beans.factory.xml;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.core.io.Resource;

@Deprecated
@SuppressWarnings({"serial", "all"})
public class XmlBeanFactory extends DefaultListableBeanFactory {

	private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
	
	public XmlBeanFactory(Resource resource) throws BeansException {
		this(resource, null);
	}
	
	public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
		super(parentBeanFactory);
		this.reader.loadBeanDefinitions(resource);
	}
}

在 XmlBeanFactory 类中真正干活的是 XmlBeanDefinitionReader (XBDR),由它去读取Xml配置文件中的Bean给我。一开始我还挺好奇它是怎么读取的,但是看到它爸爸的朋友老王 ResourceLoader,我就知道肯定是王叔叔把自己的看家本领教给它了。没过多久 XBDR 抱着一堆数据回来了,但是这密密麻麻的数据谁也看不懂,于是 XBDR 请自己的好朋友 documentLoader 帮忙把它翻译成 Doc文档(Java文件),documentLoader 再请自己的好朋友 BeanDefinitionParserDelegate,进行标签解析。

 由于加载和解析的过程并不重要,这里就只展示了流程图。具体源码自己 Debgger 下行了。我们更关心的是解析后的javaBean存储在什么地方,和Ioc容器是如何创建!


BeanDefinitionParserDelegate对默认标签的解析
package org.springframework.beans.factory.xml;

public class DefaultBeanDefinitiondocumentReader implements BeanDefinitiondocumentReader {

    
    // BDDR的好朋友,解析标签
	@Nullable
	private BeanDefinitionParserDelegate delegate;

    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		if (delegate.nodeNameEquals(ele, import_ELEMENT)) {

            // 解析 import 标签
			importBeanDefinitionResource(ele);
		}
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {

            // 解析 alias 标签
			processAliasRegistration(ele);
		}
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {

            // 解析 bean 标签
			processBeanDefinition(ele, delegate);
		}
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			
            // 解析 beans 标签
			doRegisterBeanDefinitions(ele);
		}
	}

    // 解析 bean 标签
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {

        // 好朋友的方法进行解析,经此方法,bdHolder实例已经包含配置文件中配置的各种属性,例如:Class,name,id
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {

            //如果存在默认标签的子节点下再有自定义属性,对自定义标签进行解析
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				
                //解析完后,对解析后的 bdHolder 进行注册
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			
            //通知相关的监听器,这个bean已经加载完成了
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}

}

解析标签的源码就精简一下吧?不然密密麻麻的代码看起来头疼!

public class BeanDefinitionParserDelegate {
@Nullable
	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {

        // 解析 ID
		String id = ele.getAttribute(ID_ATTRIBUTE);
        // 解析 name
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

        // 调用parseBeanDefinitionElement方法,解析其他属性
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		if (beanDefinition != null) {
			String[] aliasesArray = StringUtils.toStringArray(aliases);
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}
		return null;
	}

    @Nullable
	public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, @Nullable BeanDefinition containingBean) {

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

		String className = null;
		if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
			className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
		}
		String parent = null;
		if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
			parent = ele.getAttribute(PARENT_ATTRIBUTE);
		}

		try {

            //创建用于承载属性的 GenericBeanDefinition,它在xml文件中对应的就是Bean标签
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);
		    ...
			return bd;
		}
		finally {
			this.parseState.pop();
		}

		return null;
	}

}

这里着重讲  标签,这 个和依赖注入有关,所以单伶出来讲解。

标签

// 遍历,提取所有 constructor-arg ,然后进行解析
public class BeanDefinitionParserDelegate {
@Nullable
	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {

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

        // 提取 index 属性
		String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);

        // 提取 type 属性
		String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);

        // 提取 name 属性
		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 {
						
						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().addIndexedArgumentValue(index, valueHolder);
						
					}
					finally {
						this.parseState.pop();
					}
				}
			}
			catch (NumberFormatException ex) {
				error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
			}
		}
		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();
			}
		}
	}
}

上面的代码大概的意思是,

如果配置文件指定了index,那么操作步骤如下。

  1. 解析 constructor-arg 的子元素
  2. 使用 ConstructorArgumentValues.ValueHolder 类型来封装解析出来的元素。
  3. 将type,name和index树勋个一并封装在ConstructorArgumentValues.ValueHolder类型中并添加至当前 BeanDefinition 的 ConstructorArgumentValues 的 IndexedArgumentValue 属性中。

如果没有指定index属性,那么操作步骤如下

  1. 解析 constructor-arg 的子元素
  2. 使用 ConstructorArgumentValues.ValueHolder 类型来封装解析出来的元素。
  3. 将type,name和index树勋个一并封装在ConstructorArgumentValues.ValueHolder类型中并添加至当前 BeanDefinition 的 ConstructorArgumentValues 的 GenericArgumentValue 属性中。

等以上标签解析完毕,要做的就是注册了。​​​​​​​也就是 DefaultBeanDefinitiondocumentReader 类中方法  BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,getReaderContext().getRegistry());

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
		implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {

	@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 oldBeanDefinition;

		oldBeanDefinition = this.beanDefinitionMap.get(beanName);
		if (oldBeanDefinition != null) {
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
						"': There is already [" + oldBeanDefinition + "] bound.");
			}
			else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (this.logger.isWarnEnabled()) {
					this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
							"' with a framework-generated bean definition: replacing [" +
							oldBeanDefinition + "] with [" + beanDefinition + "]");
				}
			}
			else if (!beanDefinition.equals(oldBeanDefinition)) {
				if (this.logger.isInfoEnabled()) {
					this.logger.info("Overriding bean definition for bean '" + beanName +
							"' with a different definition: replacing [" + oldBeanDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			else {
				if (this.logger.isDebugEnabled()) {
					this.logger.debug("Overriding bean definition for bean '" + beanName +
							"' with an equivalent definition: replacing [" + oldBeanDefinition +
							"] 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 updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					this.beanDefinitionNames = updatedDefinitions;
					if (this.manualSingletonNames.contains(beanName)) {
						Set 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 (oldBeanDefinition != null || containsSingleton(beanName)) {
			resetBeanDefinition(beanName);
		}
	}

}

将bean注册至 register 中,以beanName为key,以beanDefinition 为值,注册至 register(Map)集合中。

上面的代码大概的意思是

  1. 校验
  2. 对 beanName 已经注册的情况处理。如果设置了不允许bean的覆盖,则需要抛出异常,否则直接覆盖
  3. 加入map缓存
  4. 清除解析之前留下的对应beanName的缓存

通知监听器解析

方法 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); 实现通知监听器解析。spring目前并没有对此事件做任何的逻辑处理。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/322264.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号