Spring系列一之容器初始

Spring系列一之容器初始化

一、spring的基础模块包含core、beans

  1. core模块为其他组件提供各种工具

  2. beans模块其中Bean的载体就是BeanDefinition了,我们所说的控制反转指的就是这了, 我们配置的类信息及spring内部的一些配置信息都被BeanDefinition管理着
    在这里插入图片描述

  3. 由图可以看出提供了新增BeanDefinition的入口,到此我们可以想到容器有新增入口,是否有查看、删除、修改入口呢,这让我们想到了工作当中熟悉的CRUD了,对的其实和我们工作的内容是息息相关的。



  4. 其中registerBeanDefinition()方法就是新增操作的入口了,只不过该入口是不对外开放的。说到新增入口不得不说下我们注册的bean是以什么样的形式注册到容器中呢,就以XML配置方式举例,比如一个Dog类配置如下:
    <bean id="dog" class="com.strugglesnail.factory.Dog"></bean>这样的标签我们不可能直接放入容器中的,这时我们就用到了Java核心的特性了,一切事物皆对象,将标签的各个属性封装在一个对象中,这个对象就是上图的BeanDefinition。现在我们知道BeanDefinition是什么了,接下来让我们探究它如何被加载的。
    ①、首先配置的各种bean都会以流的形式封装在Reources资源类型中
    ②、然后进行资源解析(BeanDefinitionReader)
    ③、其次会把解析的结果(BeanDefinition)存放到容器(beanDefinitionMap)
    以上就是BeanDefinition加载的大概流程。BeanDefinition是在哪加载的呢?
    首先我们先了解下BeanFactory,顾名思义就是一个Bean的工厂,工厂里会有流水线工人、各种机器及生产出的零件等。没错BeanDefinition就是在BeanFactory中解析并生产的。我们可以把配置文件看作是工厂的原材料,各种解析器可以看成工人或机器,生产出的零件可以看作BeanDefinition,仓库可以看成容器(beanDefinitionMap),这样我们就把原材料制作成了零件。



  5. 下面我们就借助代码来还原一下BeanDefinition创建的流程:
    ①、首先是加载xml配置Resource resource = new ClassPathResource("test.xml", getClass())
    ②、然后使用XmlBeanDefinitionReader解析器进行解析

	// new EncodedResource(resource):对步骤1的resource进行封装
	@Override
	public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
		return loadBeanDefinitions(new EncodedResource(resource));
	}
	
	// 将EncodedResource转换为数据流
	public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		Assert.notNull(encodedResource, "EncodedResource must not be null");
		// ...部分代码省略
		try {
			InputStream inputStream = encodedResource.getResource().getInputStream();
			try {
				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);
		}
	}

	// 根据文档信息注册beanDefinition
	protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
		try {
			Document doc = doLoadDocument(inputSource, resource);
			return registerBeanDefinitions(doc, resource);
		} catch (BeanDefinitionStoreException ex) {
			throw ex;
		}
		// ...省略其他catch
	}

	// bean定义文档解析器注册beanDefinition
	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		// 解析器初始化的时候传进来的:getRegistry()
		int countBefore = getRegistry().getBeanDefinitionCount();
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

跳转到BeanDefinitionDocumentReader解析器的registerBeanDefinitions方法:

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

	// 通过beanDefinitionParserDelegate解析器委托来解析文档
	protected void doRegisterBeanDefinitions(Element root) {
		BeanDefinitionParserDelegate parent = this.delegate;
		// 默认封装的有beanFactory、Element
		this.delegate = createDelegate(getReaderContext(), root, parent);

		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)) {
					if (logger.isInfoEnabled()) {
						logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
								"] not matching: " + getReaderContext().getResource());
					}
					return;
				}
			}
		}

		preProcessXml(root);
		// 核心方法
		parseBeanDefinitions(root, this.delegate);
		postProcessXml(root);

		this.delegate = parent;
	}

	// 解析beanDefinition
	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		if (delegate.isDefaultNamespace(root)) {
			NodeList nl = root.getChildNodes();
			// 遍历<beans>
			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)) {
						// 解析<bean>转换成beanDefinition
						parseDefaultElement(ele, delegate);
					}
					else {
						// 解析自定义标签的元素(aop的配置)
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			delegate.parseCustomElement(root);
		}
	}

	// 通过beanDefinition解析器委托类解析Element生成BeanDefinition
	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());
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			// Send registration event.
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}

我们来看一下BeanDefinitionReaderUtils这个类的registerBeanDefinition方法:

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

		// Register bean definition under primary name.
		String beanName = definitionHolder.getBeanName();
		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

		// 每个bean都可以设置多个别名,而这些别名需要存储起来
		String[] aliases = definitionHolder.getAliases();
		if (aliases != null) {
			for (String alias : aliases) {
				registry.registerAlias(beanName, alias);
			}
		}
	}

通过上图我们就能看到我们熟悉的registry.registerBeanDefinition()插入入口了,不过这个方法是由DefaultListableBeanFactory实现的,其实我们能想象的到它是如何实现的,无非是把BeanDefinition放到BeanDefinitionMap这个容器里面。下面我就用一个测试代码来注册一个bean

// 创建bean工厂
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// xml类型的bean定义解析器
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
// xml解析、生成beanDefinition及
reader.loadBeanDefinitions(new ClassPathResource("test.xml"));

这就是spring容器的初始化过程,下节我们讲下spring如何获取bean实例。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值