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

spring源码分析(4)

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

spring源码分析(4)

loadBeanDefinitions
public int loadBeanDefinitions(String location, Set actualResources) throws BeanDefinitionStoreException {
	ResourceLoader resourceLoader = getResourceLoader();
	if (resourceLoader == null) {
		throw new BeanDefinitionStoreException(
				"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
	}

	if (resourceLoader instanceof ResourcePatternResolver) {
		// Resource pattern matching available.
		try {
			Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
			int loadCount = loadBeanDefinitions(resources);
			if (actualResources != null) {
				for (Resource resource : resources) {
					actualResources.add(resource);
				}
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
			}
			return loadCount;
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException(
					"Could not resolve bean definition resource pattern [" + location + "]", ex);
		}
	}
	else {
		// Can only load single resources by absolute URL.
		Resource resource = resourceLoader.getResource(location);
		int loadCount = loadBeanDefinitions(resource);
		if (actualResources != null) {
			actualResources.add(resource);
		}
		if (logger.isDebugEnabled()) {
			logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
		}
		return loadCount;
	}
}
getResourceLoader

该方法返回的是XmlWebApplicationContext实例

因为XmlWebApplicationContext父类 AbstractApplicationContext继承了DefaultResourceLoader类 而DefaultResourceLoader实现了ResourceLoader接口,又因为ResourcePatternResolver接口继承了ResourceLoader接口 所以XmlWebApplicationContext间接实现了ResourcePatternResolver接口

if (resourceLoader instanceof ResourcePatternResolver) {

在XmlWebApplicationContext父类AbstractApplicationContext初始化时 resourcePatternResolver默认为PathMatchingResourcePatternResolver类型

public AbstractApplicationContext() {
	this.resourcePatternResolver = getResourcePatternResolver();
}
protected ResourcePatternResolver getResourcePatternResolver() {
	return new PathMatchingResourcePatternResolver(this);
}

所以这里实际上是 PathMatchingResourcePatternResolver.getResources 参数为web.xml中配置的 classpath:applicationContext.xml

Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);

public Resource[] getResources(String locationPattern) throws IOException {
	Assert.notNull(locationPattern, "Location pattern must not be null");
	// CLASSPATH_ALL_URL_PREFIX = classpath*: 显然不是classpath*开头 所以走else
	if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
		// a class path resource (multiple resources for same name possible)
		if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
			// a class path resource pattern
			return findPathMatchingResources(locationPattern);
		}
		else {
			// all class path resources with the given name
			return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
		}
	}
	else {
		// only look for a pattern after a prefix here
		// (to not get fooled by a pattern symbol in a strange prefix).
		int prefixEnd = locationPattern.indexOf(":") + 1;
		//public boolean isPattern(String path) {
		//	return (path.indexOf('*') != -1 || path.indexOf('?') != -1);
		//}
		// 判断路径中是否包含* 或者 ? 很明显这里没有所以else
		if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
			// a file pattern
			return findPathMatchingResources(locationPattern);
		}
		else {
			// a single resource with the given name
			
			return new Resource[] {getResourceLoader().getResource(locationPattern)};
		}
	}
}

因为PathMatchingResourcePatternResolver在初始化的时候构造函数默认创建的是DefaultResourceLoader类 所以这里getResourceLoader返回的是DefaultResourceLoader实例 location为classpath:applicationContext.xml

public Resource getResource(String location) {
	Assert.notNull(location, "Location must not be null");
	// no
	if (location.startsWith("/")) {
		return getResourceByPath(location);
	}
	// CLASSPATH_URL_PREFIX = classpath:   成功命中
	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 new UrlResource(url);
		}
		catch (MalformedURLException ex) {
			// No URL -> resolve as resource path.
			return getResourceByPath(location);
		}
	}
}

path为applicationContext.xml 至此getResources(location)方法返回了 一个Resource[]数组 此时实际类型ClassPathResource

public ClassPathResource(String path, ClassLoader classLoader) {
	Assert.notNull(path, "Path must not be null");
	String pathToUse = StringUtils.cleanPath(path);
	if (pathToUse.startsWith("/")) {
		pathToUse = pathToUse.substring(1);
	}
	this.path = pathToUse;
	this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
}

循环resources进行加载bean

public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
	Assert.notNull(resources, "Resource array must not be null");
	int counter = 0;
	for (Resource resource : resources) {
		counter += loadBeanDefinitions(resource);
	}
	return counter;
}

跟踪代码 调转到XmlBeanDefinitionReader的loadBeanDefinitions方法 上篇说过默认的阅读器就是XmlBeanDefinitionReader

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
	Assert.notNull(encodedResource, "EncodedResource must not be null");
	if (logger.isInfoEnabled()) {
		logger.info("Loading XML bean definitions from " + encodedResource.getResource());
	}
	// 获取当前已加载的资源
	Set currentResources = this.resourcesCurrentlyBeingLoaded.get();
	// 如果是null 则进行初始化
	if (currentResources == null) {
		currentResources = new HashSet(4);
		this.resourcesCurrentlyBeingLoaded.set(currentResources);
	}
	// 判断encodedResource是否已在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());
			}
			// 在spring中 所有实际的操作都是do开头的
			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();
		}
	}
}

doLoaddocument不需要过多解读 将xml转换成document结构 确保你的文件中使用的标签在你的文件头都有声明 并且存在对应的依赖包

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 (SAXParseException ex) {
		throw new XmlBeanDefinitionStoreException(resource.getDescription(),
				"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
	}
	catch (SAXException ex) {
		throw new XmlBeanDefinitionStoreException(resource.getDescription(),
				"XML document from " + resource + " is invalid", ex);
	}
	catch (ParserConfigurationException ex) {
		throw new BeanDefinitionStoreException(resource.getDescription(),
				"Parser configuration exception parsing XML from " + resource, ex);
	}
	catch (IOException ex) {
		throw new BeanDefinitionStoreException(resource.getDescription(),
				"IOException parsing XML document from " + resource, ex);
	}
	catch (Throwable ex) {
		throw new BeanDefinitionStoreException(resource.getDescription(),
				"Unexpected exception parsing XML document from " + resource, ex);
	}
}

这里documentReader实际上是实例化 DefaultBeanDefinitiondocumentReader类
getRegistry返回的是DefaultListableBeanFactory 而getBeanDefinitionCount返回的实际是DefaultListableBeanFactory中beanDefinitionMap的size 也就意味着已经加载的beanDefinition都会被放进beanDefinitionMap 类型是Map

public int registerBeanDefinitions(document doc, Resource resource) throws BeanDefinitionStoreException {
	BeanDefinitiondocumentReader documentReader = createBeanDefinitiondocumentReader();
	int countBefore = getRegistry().getBeanDefinitionCount();
	documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
	return getRegistry().getBeanDefinitionCount() - countBefore;
}

readerContext由createReaderContext(resource)创建 new了一个XmlReaderContext实例
doc是DeferreddocumentImpl类型

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

值得一提的是readerContext中的是从meta-INF/spring.handlers中读取的 这样spring就知道什么时候用什么处理器

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

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

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