文档章节

Spring源码-IOC容器(二)-Bean的定位解析注册

青离
 青离
发布于 2017/06/03 11:29
字数 3747
阅读 260
收藏 0
点赞 0
评论 2

Spring IOC容器 源码解析系列,建议大家按顺序阅读,欢迎讨论

(spring源码均为4.1.6.RELEASE版本)

  1. Spring源码-IOC容器(一)-构建简单IOC容器
  2. Spring源码-IOC容器(二)-Bean的定位解析注册
  3. Spring源码-IOC容器(三)-GetBean
  4. Spring源码-IOC容器(四)-FactoryBean
  5. Spring源码-IOC容器(五)-Bean的初始化
  6. Spring源码-IOC容器(六)-bean的循环依赖
  7. Spring源码-IOC容器(七)-ApplicationContext
  8. Spring源码-IOC容器(八)-NamespaceHandler与自定义xml
  9. Spring源码-IOC容器(九)-Component-Scan源码解析
  10. Spring源码-IOC容器(十)-@Autowired解析

Demo

spring中不管是ApplicationContext还是BeanFactory,要想实现IOC容器,都必须将bean在外部定义的配置信息加载到spring IOC容器中来。而这个处理过程在spring中概括起来就是:定位、解析和注册。那么在spring怎么才能完成这一操作呢,来看下面的代码(sample.xml为spring配置文件,并且放在classpath路径下)。

// 1.创建一个ioc配置文件的抽象资源
ClassPathResource resource = new ClassPathResource("sample.xml");
// 2.创建一个BeanFactory实现
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 3.创建一个载入xml文件形式的BeanDefinition读取器,并将beanFactory通过构造函数传递进去
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
// 4.读取资源配置信息,并在XmlBeanDefinitionReader中解析,将解析完的BeanDefinition注册到beanFactory中
reader.loadBeanDefinitions(resource);

这就是spring加载xml配置文件的核心代码,也就包括了上面所说的定位解析注册三大操作。同时可以看到实例化了一个DefaultListableBeanFactory,因为BeanFactory是IOC容器的基本实现,而DefaultListableBeanFactory实现了BeanFactory,它被用来维护IOC容器中bean的信息和关系。下面就来具体分析spring是如何实现Bean的定位解析和注册的。

定位

定位,顾名思义,就是找到对应的位置。而在spring中,就是获得资源的输入流。

// 1.创建一个ioc配置文件的抽象资源
ClassPathResource resource = new ClassPathResource("sample.xml");

ClassPathResource实现了Resource接口

public interface Resource extends InputStreamSource

Resource接口继承自org.springframework.core.io.InputStreamSource接口

public interface InputStreamSource {
    InputStream getInputStream() throws IOException;
}

因而可以从ClassPathResource获取配置文件的输入流,来看下具体实现

public InputStream getInputStream() throws IOException {
	InputStream is;
	// 判断class对象是否为null,存在就通过getResourceAsStream获取classpath文件输入流
	if (this.clazz != null) {
		is = this.clazz.getResourceAsStream(this.path);
	}
	// 判断class类加载器是否为null,存在就通过getResourceAsStream获取classpath文件输入流
	else if (this.classLoader != null) {
		is = this.classLoader.getResourceAsStream(this.path);
	}
	// 否则就通过系统类加载器(Bootstrap类加载器)获取classpath文件输入流
	else {
		is = ClassLoader.getSystemResourceAsStream(this.path);
	}
	if (is == null) {
		throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");
	}
	return is;
}

解析

解析指的是将spring的配置文件解析成spring内容存储的数据结构。这里的数据结构可以理解成BeanDefinition。BeanDefinition是spring中的重要接口,它维护了bean的信息在spring内部的映射。

/**
 * BeanDefinition用来描述一个bean的定义,
 * 包括bean的属性、构造函数参数以及
 * 一些具体的信息(单 实例还是多实例,是否懒加载,依赖beans)。
 *
 * @author Juergen Hoeller
 * @author Rob Harrop
 * @since 19.03.2004
 * @see ConfigurableListableBeanFactory#getBeanDefinition
 * @see org.springframework.beans.factory.support.RootBeanDefinition
 * @see org.springframework.beans.factory.support.ChildBeanDefinition
 */
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

    /**
     * 单实例
     */
    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

    /**
     * 多实例
     */
    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

    /**
     * 父BeanDefinition的name
     */
    String getParentName();

    /**
     * bean的实现的全路径名称
     */
    String getBeanClassName();

    /**
     * 工厂bean的名称
     */
    String getFactoryBeanName();

    /**
     * 工厂方法名称
     */
    String getFactoryMethodName();

    /**
     * bean的作用域
     */
    String getScope();

    /**
     * 是否懒加载
     */
    boolean isLazyInit();

    /**
     * 依赖的beans
     */
    String[] getDependsOn();

    /**
     * 是否允许被自动装配
     */
    boolean isAutowireCandidate();

    /**
     * 是否优先自动装配
     */
    boolean isPrimary();

    /**
     * 构造方法参数值
     */
    ConstructorArgumentValues getConstructorArgumentValues();

    /**
     * 属性名称与值
     */
    MutablePropertyValues getPropertyValues();


    /**
     * 是否单实例
     */
    boolean isSingleton();

    /**
     * 是否多实例
     */
    boolean isPrototype();

    /**
     * 是否抽象
     */
    boolean isAbstract();

    /**
     * 角色提示
     */
    int getRole();

    /**
     * 描述
     */
    String getDescription();

    /**
     * 资源描述
     */
    String getResourceDescription();

    /**
     * 返回原始bean,如果没有返回null
     */
    BeanDefinition getOriginatingBeanDefinition();

}

可以看到BeanDefinition定义了许多bean的重要信息,比如beanClassName,单例还是多例,是否懒加载等。在解析之前实例化了两个对象:

// 2.创建一个BeanFactory实现
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 3.创建一个载入xml文件形式的BeanDefinition读取器,并将beanFactory通过构造函数传递进去
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);

DefaultListableBeanFactory是BeanFactory的实现,BeanFactory是spring另一个重要的接口,它定义了从spring获取实例化后的bean对象的方法。

 public interface BeanFactory {

    // 标识一个FactoryBean
    String FACTORY_BEAN_PREFIX = "&";
    
    // 五种获取bean实例对象的方法
    Object getBean(String name) throws BeansException;
    <T> T getBean(String name, Class<T> requiredType) throws BeansException;
    <T> T getBean(Class<T> requiredType) throws BeansException;
    Object getBean(String name, Object... args) throws BeansException;
    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
    
    // 是否存在name的bean
    boolean containsBean(String name);
    
    // bean是否为单例
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
    
    // bean是否为多例
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
    
    // bean是否为指定的Class类型
    boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException;
    
    // 获取bean的Class类型
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;
    
    // bean的昵称
    String[] getAliases(String name);

}

来XmlBeanDefinitionReader的构造函数

public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
	super(registry);
}

它的父类是AbstractBeanDefinitionReader

protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
    // 设置BeanDefinitionRegistry,用于注册Bean
    this.registry = registry;
    
    // 决定要使用的ResourceLoader 
    if (this.registry instanceof ResourceLoader) {
    	this.resourceLoader = (ResourceLoader) this.registry;
    }
    else {
    	this.resourceLoader = new PathMatchingResourcePatternResolver();
    }
    
    // 决定要使用的Environment
    if (this.registry instanceof EnvironmentCapable) {
    	this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
    }
    else {
    	this.environment = new StandardEnvironment();
    }
}

真正的解析从下面开始

reader.loadBeanDefinitions(resource);

调用的是XmlBeanDefinitionReader的loadBeanDefinitions方法

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
	return loadBeanDefinitions(new EncodedResource(resource));
}

将Resource封装成EncodedResource

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
    try {
        // 拿到配置文件的输入流
    	InputStream inputStream = encodedResource.getResource().getInputStream();
    	try {
    	    // 封装成InputSource,设置编码
    		InputSource inputSource = new InputSource(inputStream);
    		if (encodedResource.getEncoding() != null) {
    			inputSource.setEncoding(encodedResource.getEncoding());
    		}
    		// 实际调用方法
    		return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
    	}
    	finally {
    		inputStream.close();
    	}
    }
    catch (IOException ex) {
    	throw new BeanDefinitionStoreException(
    			"IOException parsing XML document from " + encodedResource.getResource(), ex);
    }
}

实际调用的还是doLoadBeanDefinitions方法

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
	throws BeanDefinitionStoreException {
    try {
        // 解析xml文件获得Document对象
    	Document doc = doLoadDocument(inputSource, resource);
    	// 解析Document为BeanDefinition并注册到BeanFactory
    	return registerBeanDefinitions(doc, resource);
    }
}

可以看到registerBeanDefinitions方法其实综合了解析和注册两个功能。先看下解析Document。

protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
	return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
			getValidationModeForResource(resource), isNamespaceAware());
}

this.documentLoader其实是已经实例化的类变量

private DocumentLoader documentLoader = new DefaultDocumentLoader();

来看下loadDocument的实现

public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
		ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {

	DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
	if (logger.isDebugEnabled()) {
		logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
	}
	DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
	return builder.parse(inputSource);
}

spring默认使用了DOM的解析方式,通过创建DocumentBuilder来解析Document对象。再来看registerBeanDefinitions方法。

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
	BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
	documentReader.setEnvironment(getEnvironment());
	int countBefore = getRegistry().getBeanDefinitionCount();
	documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
	return getRegistry().getBeanDefinitionCount() - countBefore;
}

XmlBeanDefinitionReader将真正的解析过程委托给了BeanDefinitionDocumentReader的实现类DefaultBeanDefinitionDocumentReader。

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
	this.readerContext = readerContext;
	logger.debug("Loading bean definitions");
	Element root = doc.getDocumentElement();
	doRegisterBeanDefinitions(root);
}

从Document拿到根元素,交给doRegisterBeanDefinitions方法

protected void doRegisterBeanDefinitions(Element root) {
    // 获取父BeanDefinitionParserDelegate
    BeanDefinitionParserDelegate parent = this.delegate;
    // 创建当前BeanDefinitionParserDelegate
    this.delegate = createDelegate(getReaderContext(), root, parent);
    
    //对<beans>的profile属性进行校验
    if (this.delegate.isDefaultNamespace(root)) {
    	String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
    	if (StringUtils.hasText(profileSpec)) {
    		String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
    				profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
    		if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
    			return;
    		}
    	}
    }
    
    // 解析前扩展点
    preProcessXml(root);
    // 解析根元素
    parseBeanDefinitions(root, this.delegate);
    // 解析后扩展点
    postProcessXml(root);
    
    this.delegate = parent;
}

解析的核心就是对根元素的处理

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    // 判断元素是否为默认Namespace,即http://www.springframework.org/schema/beans
    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) {
    			Element ele = (Element) node;
    			if (delegate.isDefaultNamespace(ele)) {
    				parseDefaultElement(ele, delegate);
    			}
    			else {
    				delegate.parseCustomElement(ele);
    			}
    		}
    	}
    }
    else {
    	delegate.parseCustomElement(root);
    }
}

这个方法决定了对元素的解析是默认的还是自定义的。spring定义了_http://www.springframework.org/schema/beans_为默认命名空间,其他的都是自定义命名空间,包括context,aop,mvc。这种方式让spring可以兼容任何其他扩展,只需要实现NamespaceHandler接口,自定义解析方式。目前其他框架支持spring配置一般都是通过此种方式实现的。这个以后再专门地进行讲解,这里先来看默认的beans的解析。通过获取根元素的每个子节点,交给parseDefaultElement方法处理。

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    // import标签解析
	if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
		importBeanDefinitionResource(ele);
	}
	// alias标签解析
	else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
		processAliasRegistration(ele);
	}
	// bean标签解析
	else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
		processBeanDefinition(ele, delegate);
	}
	// 嵌套的beans标签解析
	else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
		// recurse
		doRegisterBeanDefinitions(ele);
	}
}

我们主要关注的是bean标签的解析

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
	// 委托BeanDefinitionParserDelegate解析bean标签
	BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
	if (bdHolder != null) {
		// 对自定义属性和自定义子节点进行处理
		bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
		try {
			// 注册得到的BeanDefinitionHolder到BeanFactory中
			BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
		}
		catch (BeanDefinitionStoreException ex) {
			getReaderContext().error("Failed to register bean definition with name '" +
					bdHolder.getBeanName() + "'", ele, ex);
		}
		// 发送注册完成事件通知
		getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
	}
}

委托BeanDefinitionParserDelegate来解析bean标签

    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
		// id属性,定义bean的name
		String id = ele.getAttribute(ID_ATTRIBUTE);
		// name属性,定义bean的昵称
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

		List<String> aliases = new ArrayList<String>();
		if (StringUtils.hasLength(nameAttr)) {
			String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			aliases.addAll(Arrays.asList(nameArr));
		}

		String beanName = id;
		if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
			beanName = aliases.remove(0);
			if (logger.isDebugEnabled()) {
				logger.debug("No XML 'id' specified - using '" + beanName +
						"' as bean name and " + aliases + " as aliases");
			}
		}

		if (containingBean == null) {
			checkNameUniqueness(beanName, aliases, ele);
		}
		// 解析bean的属性及字节点
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		if (beanDefinition != null) {
			String[] aliasesArray = StringUtils.toStringArray(aliases);
			// 创建BeanDefinitionHolder保存信息
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}

		return null;
	}

bean的属性和子节点的解析

	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);
			}
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);
			
			// 其他属性的解析
			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
			// bean的描述信息
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
			// meta信息
			parseMetaElements(ele, bd);
			// lookup-method设置
			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
			// replaced-method设置
			parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

			// 构造函数设置
			parseConstructorArgElements(ele, bd);
			// property信息
			parsePropertyElements(ele, bd);
			// qualifier信息
			parseQualifierElements(ele, bd);

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

			return bd;
		}
		catch (ClassNotFoundException ex) {
			error("Bean class [" + className + "] not found", ele, ex);
		}
		catch (NoClassDefFoundError err) {
			error("Class that bean class [" + className + "] depends on not found", ele, err);
		}
		catch (Throwable ex) {
			error("Unexpected failure during bean definition parsing", ele, ex);
		}
		finally {
			this.parseState.pop();
		}

		return null;
	}

先来看常见的属性的解析

    public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
			BeanDefinition containingBean, AbstractBeanDefinition bd) {

		// singleton属性,早期使用,被scope取代
		if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
			error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
		}
		// scope属性,默认为singleton单例
		else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
			bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
		}
		else if (containingBean != null) {
			// Take default from containing bean in case of an inner bean definition.
			bd.setScope(containingBean.getScope());
		}

		// abstract属性,为true则不会实例化
		if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
			bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
		}

		// lazy-init属性,是否懒加载
		String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
		if (DEFAULT_VALUE.equals(lazyInit)) {
			lazyInit = this.defaults.getLazyInit();
		}
		bd.setLazyInit(TRUE_VALUE.equals(lazyInit));

		// autowire属性,这里并不是@Autowired的配置
		String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
		bd.setAutowireMode(getAutowireMode(autowire));

		// dependency-check属性
		String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
		bd.setDependencyCheck(getDependencyCheck(dependencyCheck));

		// depends-on属性
		if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
			String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
			bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
		}

		// autowire-candidate属性
		String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
		if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) {
			String candidatePattern = this.defaults.getAutowireCandidates();
			if (candidatePattern != null) {
				String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
				bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
			}
		}
		else {
			bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
		}

		// primary属性
		if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
			bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
		}

		// init-method, 实例化后执行
		if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
			String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
			if (!"".equals(initMethodName)) {
				bd.setInitMethodName(initMethodName);
			}
		}
		else {
			if (this.defaults.getInitMethod() != null) {
				bd.setInitMethodName(this.defaults.getInitMethod());
				bd.setEnforceInitMethod(false);
			}
		}

		// destroy-method属性,对象销毁前执行
		if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
			String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
			if (!"".equals(destroyMethodName)) {
				bd.setDestroyMethodName(destroyMethodName);
			}
		}
		else {
			if (this.defaults.getDestroyMethod() != null) {
				bd.setDestroyMethodName(this.defaults.getDestroyMethod());
				bd.setEnforceDestroyMethod(false);
			}
		}

		// factory-method属性,可以通过工厂方法创建实例
		if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
			bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
		}
		// factory-bean属性
		if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
			bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
		}

		return bd;
	}

然后是property标签的解析

	public void parsePropertyElement(Element ele, BeanDefinition bd) {
		// Property的名称
		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;
			}
			// 解析property的值
			Object val = parsePropertyValue(ele, bd, propertyName);
			// 组装PropertyValue对象
			PropertyValue pv = new PropertyValue(propertyName, val);
			parseMetaElements(ele, pv);
			pv.setSource(extractSource(ele));
			// 添加到BeanDefinition的PropertyValues集合中
			bd.getPropertyValues().addPropertyValue(pv);
		}
		finally {
			this.parseState.pop();
		}
	}

property的值可以是value或者ref或者是子节点

	public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
		String elementName = (propertyName != null) ?
						"<property> element for property '" + propertyName + "'" :
						"<constructor-arg> element";

		// Should only have one child element: ref, value, list, etc.
		NodeList nl = ele.getChildNodes();
		Element subElement = null;
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
			if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
					!nodeNameEquals(node, META_ELEMENT)) {
				// Child element is what we're looking for.
				if (subElement != null) {
					error(elementName + " must not contain more than one sub-element", ele);
				}
				else {
					subElement = (Element) node;
				}
			}
		}
		
		// ref属性
		boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
		// value属性
		boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
		if ((hasRefAttribute && hasValueAttribute) ||
				((hasRefAttribute || hasValueAttribute) && subElement != null)) {
			error(elementName +
					" is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
		}

		if (hasRefAttribute) {
			String refName = ele.getAttribute(REF_ATTRIBUTE);
			if (!StringUtils.hasText(refName)) {
				error(elementName + " contains empty 'ref' attribute", ele);
			}
			// 如果是ref属性,返回RuntimeBeanReference对象
			RuntimeBeanReference ref = new RuntimeBeanReference(refName);
			ref.setSource(extractSource(ele));
			return ref;
		}
		else if (hasValueAttribute) {
			// 如果是value属性,转化成String
			TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
			valueHolder.setSource(extractSource(ele));
			return valueHolder;
		}
		else if (subElement != null) {
			// 如果有子节点,继续解析
			return parsePropertySubElement(subElement, bd);
		}
		else {
			// Neither child element nor "ref" or "value" attribute found.
			error(elementName + " must specify a ref or value", ele);
			return null;
		}
	}

对于存在子节点的继续解析

	public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
		// 自定义的标签调用自定义的解析方法
		if (!isDefaultNamespace(ele)) {
			return parseNestedCustomElement(ele, bd);
		}
		// bean标签
		else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
			BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
			if (nestedBd != null) {
				nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
			}
			return nestedBd;
		}
		// ref标签
		else if (nodeNameEquals(ele, REF_ELEMENT)) {
			// A generic reference to any name of any bean.
			String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
			boolean toParent = false;
			if (!StringUtils.hasLength(refName)) {
				// A reference to the id of another bean in the same XML file.
				refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);
				if (!StringUtils.hasLength(refName)) {
					// A reference to the id of another bean in a parent context.
					refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
					toParent = true;
					if (!StringUtils.hasLength(refName)) {
						error("'bean', 'local' or 'parent' is required for <ref> element", ele);
						return null;
					}
				}
			}
			if (!StringUtils.hasText(refName)) {
				error("<ref> element contains empty target attribute", ele);
				return null;
			}
			RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
			ref.setSource(extractSource(ele));
			return ref;
		}
		// idref标签
		else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
			return parseIdRefElement(ele);
		}
		// value标签
		else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
			return parseValueElement(ele, defaultValueType);
		}
		// null标签
		else if (nodeNameEquals(ele, NULL_ELEMENT)) {
			// It's a distinguished null value. Let's wrap it in a TypedStringValue
			// object in order to preserve the source location.
			TypedStringValue nullHolder = new TypedStringValue(null);
			nullHolder.setSource(extractSource(ele));
			return nullHolder;
		}
		// array标签
		else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
			return parseArrayElement(ele, bd);
		}
		// list标签
		else if (nodeNameEquals(ele, LIST_ELEMENT)) {
			return parseListElement(ele, bd);
		}
		// set标签	
		else if (nodeNameEquals(ele, SET_ELEMENT)) {
			return parseSetElement(ele, bd);
		}
		// map标签
		else if (nodeNameEquals(ele, MAP_ELEMENT)) {
			return parseMapElement(ele, bd);
		}
		// props标签
		else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
			return parsePropsElement(ele);
		}
		else {
			error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
			return null;
		}
	}

至此所有xml的解析就完成了,接下来就是Bean Definition的注册。

注册

在DefaultBeanDefinitionDocumentReader的processBeanDefinition中,解析完xml后会拿到BeanDefinition信息的持有类BeanDefinitionHolder。

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
	// 委托BeanDefinitionParserDelegate解析bean标签
	BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
	if (bdHolder != null) {
		// 对自定义属性和自定义子节点进行处理
		bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
		try {
			// 注册得到的BeanDefinitionHolder到BeanFactory中
			BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
		}
		catch (BeanDefinitionStoreException ex) {
			getReaderContext().error("Failed to register bean definition with name '" +
					bdHolder.getBeanName() + "'", ele, ex);
		}
		// 发送注册完成事件通知
		getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
	}
}

通过BeanDefinitionReaderUtils.registerBeanDefinition注册到BeanFactory。

	public static void registerBeanDefinition(
			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
			throws BeanDefinitionStoreException {

		// bean的名称
		String beanName = definitionHolder.getBeanName();
		// 注册BeanDefinition到DefaultListableBeanFactory
		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

		// 注册bean的昵称
		String[] aliases = definitionHolder.getAliases();
		if (aliases != null) {
			for (String alias : aliases) {
				registry.registerAlias(beanName, alias);
			}
		}
	}

这里的registry其实就是DefaultListableBeanFactory,它实现了BeanDefinitionRegistry接口,并被一直传递到这里。DefaultListableBeanFactory的registerBeanDefinition实现:

	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		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) {
			// 校验部分省略
		}
		else {
			this.beanDefinitionNames.add(beanName);
			this.manualSingletonNames.remove(beanName);
			this.frozenBeanDefinitionNames = null;
		}
		// 添加到BeanDefinitionMap
		this.beanDefinitionMap.put(beanName, beanDefinition);

		if (oldBeanDefinition != null || containsSingleton(beanName)) {
			resetBeanDefinition(beanName);
		}
	}

这里的beanDefinitionMap就是存储BeanDefinition数据的核心Map.

	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);

至此spring的xml配置文件经过定位,解析和注册,映射成为spring内部的数据结构。上面我们曾提到spring的BeanFactory核心接口,其中的核心方法就是getBean,spring如何实例化、配置以及组装Bean对象,以及Bean对象之间的依赖关系是如何注入,请看下一章。

© 著作权归作者所有

共有 人打赏支持
青离
粉丝 261
博文 47
码字总数 104472
作品 0
海淀
后端工程师
加载中

评论(2)

青离
青离

引用来自“MarkYao”的评论

Resource接口继承自java.io.InputStreamSource接口应该修改为org.springframework.core.io.InputStreamSource接口
已改正,感谢
MarkYao
MarkYao
Resource接口继承自java.io.InputStreamSource接口应该修改为org.springframework.core.io.InputStreamSource接口
深入理解Spring源码(一)-IOC容器的定位,载入,注册

前言:Spring源码继承,嵌套层次非常多,读起来非常容易晕,小伙伴们在看文章的时候一定要跟着文章的思路自己去源码里点一点,看一看,并且多看几次。就会越来越清晰。下面开始正题 1.Spring...

Meet相识_bfa5 ⋅ 05/01 ⋅ 0

Spring IOC 实现原理

Spring IOC 实现原理 IOC: Inversion of Control ,即 "控制反转" , 不是什么技术,而是一种思想。原先需要自行实例化的对象, 交给IOC容器去实现。那么控制反转,谁被控制? 谁被反转 ? 在...

起个名忒难 ⋅ 05/17 ⋅ 0

2.3 IoC容器的初始化过程

简单来说,IoC容器的初始化是由前面介绍的refresh()方法来启动的,这个启动包括BeanDefinition的Resource定位、载入和注册。 (1) Resource定位过程: 指的是BeanDefinition的资源定位,由Res...

edwardGe ⋅ 05/27 ⋅ 0

Spring源码解析系列之IOC容器(一)

前言 实际上我所有的博客都是原来对原来印象笔记里笔记内容的加工,关于Spring源码自己已经解析了很多遍,但是时间长总是忘记,写一篇博客权当加强记忆,也算再次学习下大师们的设计思想,思...

后厂村老司机 ⋅ 06/02 ⋅ 0

spring-ioc分析

BeanFactory和ApplicationContext BeanFactory和ApplicationContext都是容器,BeanFactory是最基础的容器,里面定义了一些最基本的方法: 而Application也同样是容器,对比与BeanFactory来说...

sendo ⋅ 01/23 ⋅ 0

Spring Bean注册解析(一)

Spring是通过IoC容器对Bean进行管理的,而Bean的初始化主要分为两个过程:Bean的注册和Bean实例化。Bean的注册主要是指Spring通过读取配置文件获取各个bean的声明信息,并且对这些信息进行注...

张旭峰 ⋅ 05/12 ⋅ 0

深入研究Spring-IoC:源码分析容器创建

1.前言 从之前的分析中可以知道IOC容器的创建大致分为3步:Resource定位、BeanDefinition载入解析、向容器注册BeanDefinition。 Tiny-spring手动实现了Spring框架,通过对这个源码的解读可以...

mengdonghui123456 ⋅ 2017/08/24 ⋅ 0

IoC 容器的初始化之 BeanDefinition 的载入和解析

在上一篇文章,我们讲了 IoC 容器初始化的准备阶段,即找到 BeanDefinition 的 Resource 定位,就好比我们用水桶打水,首先要找到水源所在。找到水源之后,我们关注的就是打水的过程了,相比...

偷星辰夜 ⋅ 2017/11/27 ⋅ 0

Spring源码--IoC容器创建过程

我们都知道Spring的核心就是AOP和IoC,Spring官网同时也说明它的思想是:BOP(Bean Oriented Programming)。今天我们就先讲讲IoC容器创建的时候都干了什么东西?原理是什么样的?以Spring5...

lyz812672598 ⋅ 04/24 ⋅ 0

Spring容器启动过程

搞了一年多的Java了,每个项目都在用Spring,这几天没事看了看Spring源码,总结了下Spring容器的启动过程,想把它记录下来,免得忘了 spring容器的启动方式有两种: 1、自己提供Application...

冰心无影 ⋅ 2017/05/27 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

jsonrpc-4j代码解析

解析文件 AutoJsonRpcServiceImplExporter JsonServiceExporter AutoJsonRpcServiceImplExporter 路径:com.googlecode.jsonrpc4j.spring.AutoJsonRpcServiceImplExporter AutoJsonRpcServi......

郭恩洲_OSC博客 ⋅ 42分钟前 ⋅ 0

百度搜索

from selenium import webdriver import time brower=webdriver.Firefox() brower.get('http://www.baidu.com') input=brower.find_element_by_id('kw') input.send_keys('中南大学') time.s......

南桥北木 ⋅ 48分钟前 ⋅ 0

tomcat 日志记录器

1、日志记录器是记录消息的组件 日志记录器需要与某个servlet 容器相关联 2、Logger 接口 共定义了5种日志级别:FATAL、ERROR、WARNING、INFORMATION、DEBUGGER setVerbosity 设置级别 setC...

职业搬砖20年 ⋅ 50分钟前 ⋅ 0

Thrift RPC实战(三) Thrift序列化机制

1.Thrift基础架构 Thrift是一个客户端和服务端的架构体系,数据通过socket传输; 具有自己内部定义的传输协议规范(TProtocol)和传输数据标准(TTransports); 通过IDL脚本对传输数据的数据结构...

lemonLove ⋅ 50分钟前 ⋅ 0

网站建设就要像2018世界杯的俄罗斯队大杀四方[图]

今天心情不错,因为昨天晚上观看了世界杯比赛,尤其是对俄罗斯队的大杀四方感到十分霸气侧漏啊,因此我联想到了自己的博客网站,我的博客是去年年底上线的,一直想建设一个关于读书和读后感作...

原创小博客 ⋅ 59分钟前 ⋅ 0

Greenplum 三节点安装教程(非root用户)

Greenplum 三节点安装教程(非root用户) 环境准备 安装vmware,装三台centos 虚拟机设置: 主机名 IP 内存 硬盘 node1 Xxx1 2G 80G node2 Xxx2 2G 80G node3 Xxx3 2G 80G CSDN下载greenplum...

仔仔1993 ⋅ 59分钟前 ⋅ 0

linux 信号机制

signal(SIGPIPE, SIG_IGN); TCP是全双工的信道, 可以看作两条单工信道, TCP连接两端的两个端点各负责一条. 当对端调用close时, 虽然本意是关闭整个两条信道, 但本端只是收到FIN包. 按照TCP协...

xxdd ⋅ 今天 ⋅ 0

SpringWind

环境搭建和系统部署

颖伙虫 ⋅ 今天 ⋅ 0

vim命令用法

第五章 vim命令 vim和vi几乎是一样的,唯一的区别就是当编辑一个文本时,使用vi不会显示颜色,而使用vim会显示颜色。 vim有三个模式:一般模式,编辑模式,命令模式。 系统最小化安装时没有安...

弓正 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部