Spring源码解析-4、IOC容器初始化

IOC容器初始化的几个步骤

IOC容器的初始化由以下三个步骤构成:
1、BeanDefinition的Resource定位
由ResourceLoader通过统一的Resource接口来完成,Resource对不同形式的BeanDefinition有统一的接口。
比如文件系统中的BeanDefinition信息由FileSystemResourceLoader获取FileSystemResource来代表。
在类路径下的BeanDefinition信息由DefaultResourceLoader 获取的ClassPathResource来代表
2、BeanDefinition的载入解析
载入解析的过程就是把Resource中定义的Bean表示成IOC容器中的内部结构BeanDefinition。
3、BeanDefinition在IOC容器中的注册
将BeanDefinition通过BeanDefinitionRegisty注册到IOC容器中去.注册的过程,其实就是讲解析得到的BeanDefinition维护到IOC持有的一个HashMap上。

什么是BeanDefinition

BeanDefinition 就是Resource中定义的Bean在IOC容器中的抽象表示,通过这个数据结构,实现对IOC容器中Bean的管理。

为什么要拿ApplicationContext来讲IOC容器的初始化?

前面了解过编程式初始化IOC容器的方法,简单来说,需要创建一个默认IOC容器,一个Resource对象,一个持有IOC容器引用的BeanDefinitionReader对象,然后用这个BeanDefinitionReader对象来为IOC容器初始化Resource中的BeanDefinition对象。
使用DefaultListableBeanFactory的优势是可以灵活的使用自己的IOC容器,但是缺点就是比较麻烦。
而我们常用的ApplicationContext除了具备普通IOC容器存储Bean的功能,还通过继承和实现,持有ResourceLoader【资源定位加载】,MessageSource【国际化】,ApplicationEventPublisher【事件发布订阅】,具备一些高级的功能,同时简化IOC容器的初始化,因此今天的学习从ApplicationContext的FileSystemXmlApplicationContext来深入。

BeanDefinition的Resource定位

public FileSystemXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {
		//设置双亲容器
		super(parent);
		//多个资源定位
		setConfigLocations(configLocations);
		//是否要初始化
		if (refresh) {
		//实际的初始化操作
			refresh();
		}
	}

如上,FileSystemXmlApplicationContext支持多个资源定位。
可以通过refresh指定是否要进行容器的初始化。
refresh 方法在AbstractApplicationContext【注意这个方法类继承自DefaultResourceLoader,因而具备资源定位加载的能力】中。

//关注这一行
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

obtainFreshBeanFactory最终调用到AbstractRefreshableApplicationContext的 refreshBeanFactory

protected final void refreshBeanFactory() throws BeansException {
//是否已经有Bean容器
		if (hasBeanFactory()) {
		//有就销毁并关闭容器
			destroyBeans();
			closeBeanFactory();
		}
		try {
		//创建容器,可以看到,其实也是创建DefaultListableBeanFactory
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
			//加载BeanDefinition
			loadBeanDefinitions(beanFactory);
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

loadBeandefinition最终调用到AbstractBeanDefinitionReader的loadBeandefinition

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

		if (resourceLoader instanceof ResourcePatternResolver) {
			// Resource pattern matching available.
			try {
				Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
				int count = loadBeanDefinitions(resources);
				if (actualResources != null) {
					Collections.addAll(actualResources, resources);
				}
				if (logger.isTraceEnabled()) {
					logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
				}
				return count;
			}
			catch (IOException ex) {
				throw new BeanDefinitionStoreException(
						"Could not resolve bean definition resource pattern [" + location + "]", ex);
			}
		}
		else {
			// Can only load single resources by absolute URL.
			//通过DefaultResourceLoader的getResource方法来获取资源定位
			Resource resource = resourceLoader.getResource(location);
			int count = loadBeanDefinitions(resource);
			if (actualResources != null) {
				actualResources.add(resource);
			}
			if (logger.isTraceEnabled()) {
				logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
			}
			return count;
		}
	}

DefaultResourceLoader的getResource方法如下:

public Resource getResource(String location) {
		Assert.notNull(location, "Location must not be null");

		for (ProtocolResolver protocolResolver : this.protocolResolvers) {
			Resource resource = protocolResolver.resolve(location, this);
			if (resource != null) {
				return resource;
			}
		}

		if (location.startsWith("/")) {
			return getResourceByPath(location);
		}
		//类路径下的资源
		else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
			return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
		}
		else {
			try {
				// Try to parse the location as a URL...
				URL url = new URL(location);
				return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
			}
			catch (MalformedURLException ex) {
				// No URL -> resolve as resource path.
				return getResourceByPath(location);
			}
		}
	}

最终调用到getResourceByPath,

//饶了一大圈,确实掉了FileSystemXmlApplicationContext中的getResourceByPath,
得到FileSystemResource对象
protected Resource getResourceByPath(String path) {
		if (path.startsWith("/")) {
			path = path.substring(1);
		}
		return new FileSystemResource(path);
	}

简而言之:
BeanDefinition的资源定位通过DefaultResourceLoader的getResource实现,对于URI、Classpath下的资源有特殊处理,其他都会走到对应的getResourceByPath去实现个性化的资源定位。

BeanDefinition的载入解析

BeanDefinition的载入解析有XmlBeanDefinitionReader来实现

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		Assert.notNull(encodedResource, "EncodedResource must not be null");
		if (logger.isTraceEnabled()) {
			logger.trace("Loading XML bean definitions from " + encodedResource);
		}

		Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
		if (currentResources == null) {
			currentResources = new HashSet<>(4);
			this.resourcesCurrentlyBeingLoaded.set(currentResources);
		}
		if (!currentResources.add(encodedResource)) {
			throw new BeanDefinitionStoreException(
					"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
		}
		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);
		}
		finally {
			currentResources.remove(encodedResource);
			if (currentResources.isEmpty()) {
				this.resourcesCurrentlyBeingLoaded.remove();
			}
		}
	}

loadBeanDefinitions实际调用了doLoadBeanDefinitions

//将资源转成document对象
Document doc = doLoadDocument(inputSource, resource);
//解析并且注册BeanDefinition到容器,返回注册的数量
int count = registerBeanDefinitions(doc, resource);

registerBeanDefinitions

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//获取BeanDefinitionDocumentReader对象
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		int countBefore = getRegistry().getBeanDefinitionCount();
		//用DocumentReader去解析注册对象
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

documentReader.registerBeanDefinitions
最终调用到doRegisterBeanDefinitions

protected void doRegisterBeanDefinitions(Element root) {
		//这个类用来解析document里的spring标签
		BeanDefinitionParserDelegate parent = this.delegate;
		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);
				// We cannot use Profiles.of(...) since profile expressions are not supported
				// in XML config. See SPR-12458 for details.
				if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
					if (logger.isDebugEnabled()) {
						logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
								"] not matching: " + getReaderContext().getResource());
					}
					return;
				}
			}
		}

		preProcessXml(root);
		//解析BeanDefinition
		parseBeanDefinitions(root, this.delegate);
		postProcessXml(root);

		this.delegate = parent;
	}

parseBeanDefinitions 调用到parseDefaultElement,根据不同的标签,走不同的处理方法

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
		//bean标签,实现Bean的载入
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			doRegisterBeanDefinitions(ele);
		}
	}

最终调用到processBeanDefinition

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//解析得到BeanDefinitionHolder持有BeanDefinition、BeanName以及别名
		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));
		}
	}

简而言之:
BeanDefinition的载入解析过程可以概括如下:
1、先将Xml的Resource解析为Document对象
2、使用DocumentReader来实现Spring中Bean解析,其中DocumentReader把Bean解析的具体步骤委托BeanDefinitionParserDelegate来做
3、BeanDefinitionParserDelegate解析得到BeanDefinitionHolder对象,
BeanDefinitionHolder持有BeanDefinition、BeanName和别名,然后使用DefaultListableBeanFactory中实现的BeanDefinitionRegistry来进行BeanDefinition的注册。

BeanDefinition在IOC容器中的注册

从上面的BeanDefinition的载入和解析过程中,已经得知BeanDefinition载入的入口,来具体看下这边的注册怎么实现的?

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

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

		// Register aliases for bean name, if any.
		String[] aliases = definitionHolder.getAliases();
		if (aliases != null) {
			for (String alias : aliases) {
			//注册别名
				registry.registerAlias(beanName, alias);
			}
		}
	}

BeanDefinitionRegistry其实就是DefaultListableBeanFactory本身,因为他实现这个接口。

registry.registerBeanDefinition




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 existingDefinition = this.beanDefinitionMap.get(beanName);
		if (existingDefinition != null) {
		//如果这个bean已存在,是否允许覆盖
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
			}
			else if (existingDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (logger.isInfoEnabled()) {
					logger.info("Overriding user-defined bean definition for bean '" + beanName +
							"' with a framework-generated bean definition: replacing [" +
							existingDefinition + "] with [" + beanDefinition + "]");
				}
			}
			else if (!beanDefinition.equals(existingDefinition)) {
				if (logger.isDebugEnabled()) {
					logger.debug("Overriding bean definition for bean '" + beanName +
							"' with a different definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			else {
				if (logger.isTraceEnabled()) {
					logger.trace("Overriding bean definition for bean '" + beanName +
							"' with an equivalent definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			//把BeanDefinition存入map
			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<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					this.beanDefinitionNames = updatedDefinitions;
					if (this.manualSingletonNames.contains(beanName)) {
						Set<String> 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 (existingDefinition != null || containsSingleton(beanName)) {
			resetBeanDefinition(beanName);
		}
	}

如下可知BeanDefinition被维护在一个Map内。
同理别名维护在aliasMap。

简而言之:BeanDefinition的注册过程
1、把BeanDefinition维护进一个容器持有的Map
2、把Alias维护进另一个容器持有的Map

猜你喜欢

转载自blog.csdn.net/qq_28605513/article/details/85322241