Spring源码分析 1:配置文件解析

Spring

spring项目搭建

1. 导入jar依赖

  • spring中最核心的4个jar
    spring-beans
    spring-core
    spring-context
    spring-expression
  • 一个最最简单的spring工程,理论上就只需要一个jar就够了
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
	<version>${spring.version}</version>
</dependency>
  • spring日志jar
<dependency>
	<groupId>ch.qos.logback</groupId>
	<artifactId>logback-classic</artifactId>
	<version>LATEST</version>
</dependency>

在这里插入图片描述

2. XSD引入

  • spring中要引入自定义标签,必须要引入其对应的XSD文件,XSD 是编写 xml 文件的一种规范,有了这个规范才能校验 xml 是否写错;
  • 例如要引入自定义标签<context:component-scan base-package="org.example"/>,就必须引入这个标签对应的 XSD 文件。

在这里插入图片描述

  • 在标签对应的jar包下面找到对应的spring.schemas,在这个文件中就会有对应的XSD路径和命名空间。

在这里插入图片描述

3. spring 容器加载方式

1、类路径获取配置文件
ApplicationContext applicationContext= new ClassPathXmlApplicationContext("spring.xml");

2、文件系统路径获取配置文件【绝对路径】
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("E:\\idea\\public\\springdemo\\src\\main\\resources\\spring.xml");

3、无配置文件加载容器
ApplicationContext applicationContext = new AnnotationConfigApplicationContext("org.example");

4、springboot加载容器
ApplicationContext applicationContext = new EmbeddedWebApplicationContext();

源码精读

1. 容器加载核心方法

  • AbstractApplicationContext.refresh()方法,是spring容器启动过程中的核心方法,spring容器要加载必须执行该方法。

2. 测试类

  • 实体Student

在这里插入图片描述

  • 容器加载

在这里插入图片描述

  • spring.xml

在这里插入图片描述

  • 打印结果

在这里插入图片描述

xml解析

  • 进入构造方法ClassPathXmlApplicationContext

在这里插入图片描述

  • 进入this

在这里插入图片描述

  • setConfigLocations(configLocations);----创建解析器,设置configLocations

在这里插入图片描述

3.1 核心方法AbstractApplicationContext#refresh()

在这里插入图片描述

public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		//为容器初始化做准备,重要程度:0
		// Prepare this context for refreshing.
		prepareRefresh();

		/**重要程度:5
		* 1、创建BeanFactory对象
		* 2、xml解析
		* 	传统标签解析:bean、import等
		* 	自定义标签解析 如:<context:component-scan base-package="org.example"/>
		* 	自定义标签解析流程:
		* 		a、根据当前解析标签的头信息找到对应的namespaceUri
		* 		b、加载spring所以jar中的spring.handlers文件。并建立映射关系
		* 		c、根据namespaceUri从映射关系中找到对应的实现了NamespaceHandler接口的类
		* 		d、调用类的init方法,init方法是注册了各种自定义标签的解析类
		* 		e、根据namespaceUri找到对应的解析类,然后调用paser方法完成标签解析
		* 3、把解析出来的xml标签封装成BeanDefinition对象
		*/
		// Tell the subclass to refresh the internal bean factory.
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		/*
		* 给beanFactory设置一些属性值,可以不看
		* */
		// Prepare the bean factory for use in this context.
		prepareBeanFactory(beanFactory);

		try {
			// Allows post-processing of the bean factory in context subclasses.
			postProcessBeanFactory(beanFactory);

			/*
			* BeanDefinitionRegistryPostProcessor
			* BeanFactoryPostProcessor
			* 完成对这两个接口的调用
			*/
			// Invoke factory processors registered as beans in the context.
			invokeBeanFactoryPostProcessors(beanFactory);

			/*
			* 把实现了BeanPostProcessor接口的类实例化,并且加入到BeanFactory中
			*/
			// Register bean processors that intercept bean creation.
			registerBeanPostProcessors(beanFactory);

			/*
			* 国际化,重要程度2
			*/
			// Initialize message source for this context.
			initMessageSource();

			//初始化事件管理类
			// Initialize event multicaster for this context.
			initApplicationEventMulticaster();

			//这个方法着重理解模板设计模式,因为在springboot中,这个方法是用来做内嵌tomcat启动的
			// Initialize other special beans in specific context subclasses.
			onRefresh();

			/*
			* 往事件管理类中注册事件类
			*/
			// Check for listener beans and register them.
			registerListeners();

			/*
			* 这个方法是spring中最重要的方法,没有之一
			* 所以这个方法一定要理解要具体看
			* 1、bean实例化过程
			* 2、ioc
			* 3、注解支持
			* 4、BeanPostProcessor的执行
			* 5、Aop的入口
			*/
			// Instantiate all remaining (non-lazy-init) singletons.
			finishBeanFactoryInitialization(beanFactory);

			// Last step: publish corresponding event.
			finishRefresh();
		}

		catch (BeansException ex) {
			if (logger.isWarnEnabled()) {
				logger.warn("Exception encountered during context initialization - " +
						"cancelling refresh attempt: " + ex);
			}

			// Destroy already created singletons to avoid dangling resources.
			destroyBeans();

			// Reset 'active' flag.
			cancelRefresh(ex);

			// Propagate exception to caller.
			throw ex;
		}

		finally {
			// Reset common introspection caches in Spring's core, since we
			// might not ever need metadata for singleton beans anymore...
			resetCommonCaches();
		}
	}
}

3.2 obtainFreshBeanFactory()

  • 该方法主要进行xml解析工作,流程如下:
    1、创建XmlBeanDefinitionReader对象
    2、通过Reader对象加载配置文件
    3、根据加载的配置文件把配置文件封装成document对象
    4、创建BeanDefinitionDocumentReader对象,DocumentReader负责对document对象解析
    5、parseDefaultElement(ele, delegate);负责常规标签解析
    6、delegate.parseCustomElement(ele);负责自定义标签解析
    7、最终解析的标签封装成BeanDefinition并缓存到容器中

在这里插入图片描述

  • 进入obtainFreshBeanFactory()

在这里插入图片描述

  • 进入refreshBeanFactory();
  • 这里spring使用了模板设计模式,通过子类实现钩子方法来干预父类的业务执行流程。

在这里插入图片描述

3.3 AbstractRefreshableApplicationContext#refreshBeanFactory()

在这里插入图片描述

protected final void refreshBeanFactory() throws BeansException {

	//如果BeanFactory不为空,则清除BeanFactory和里面的实例
	if (hasBeanFactory()) {
		destroyBeans();
		closeBeanFactory();
	}
	try {
		// 1.创建DefaultListableBeanFactory
		//BeanFactory 实例工厂
		DefaultListableBeanFactory beanFactory = createBeanFactory();
		beanFactory.setSerializationId(getId());

		// 2.设置是否可以循环依赖 allowCircularReferences
		//是否允许使用相同名称重新注册不同的bean实现.
		customizeBeanFactory(beanFactory);

		// 3.解析xml,并把xml中的标签封装成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);
	}
}

3.3.1 AbstractXmlApplicationContext#loadBeanDefinitions(beanFactory);

  • 创建XmlBeanDefinitionReader对象

在这里插入图片描述

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
	// Create a new XmlBeanDefinitionReader for the given BeanFactory.
	//创建xml的解析器,这里是一个委托模式
	XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

	// Configure the bean definition reader with this context's
	// resource loading environment.
	beanDefinitionReader.setEnvironment(this.getEnvironment());

	//这里传一个this进去,因为ApplicationContext是实现了ResourceLoader接口的
	beanDefinitionReader.setResourceLoader(this);
	beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

	// Allow a subclass to provide custom initialization of the reader,
	// then proceed with actually loading the bean definitions.
	initBeanDefinitionReader(beanDefinitionReader);

	//主要看这个方法  重要程度 5
	loadBeanDefinitions(beanDefinitionReader);
}

3.3.2 AbstractXmlApplicationContext#loadBeanDefinitions(beanDefinitionReader);

  • 后面会多次调用好几个类中的loadBeanDefinitions这个方法
  • 通过Reader对象加载配置文件

在这里插入图片描述

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
	Resource[] configResources = getConfigResources();
	if (configResources != null) {
		reader.loadBeanDefinitions(configResources);
	}
	//获取需要加载的xml配置文件
	String[] configLocations = getConfigLocations();
	if (configLocations != null) {
		reader.loadBeanDefinitions(configLocations);
	}
}

3.3.3 AbstractBeanDefinitionReader#loadBeanDefinitions(configLocations);

在这里插入图片描述

public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
	Assert.notNull(locations, "Location array must not be null");
	int count = 0;
	//配置文件有多个,加载多个配置文件
	for (String location : locations) {
		count += loadBeanDefinitions(location);
	}
	return count;
}

3.3.4 AbstractBeanDefinitionReader#loadBeanDefinitions(location);

在这里插入图片描述

3.3.5 AbstractBeanDefinitionReader#loadBeanDefinitions(location, null);

在这里插入图片描述

  • 用流的方式加载配置文件,然后封装成Resource对象
//把字符串类型的xml文件路径,形如:classpath*:user/**/*-context.xml,转换成Resource对象类型
//其实就是用流的方式加载配置文件,然后封装成Resource对象,不重要,可以不看
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);

//主要看这个方法 ** 重要程度 5
int count = loadBeanDefinitions(resources);

在这里插入图片描述

3.3.6 AbstractBeanDefinitionReader#loadBeanDefinitions(resources);

  • 模板设计模式,钩子方法

在这里插入图片描述

3.3.7 XmlBeanDefinitionReader#loadBeanDefinitions(new EncodedResource(resource))

  • EncodedResource带编码的对Resource对象的封装

在这里插入图片描述

3.3.8 XmlBeanDefinitionReader#doLoadBeanDefinitions(inputSource, encodedResource.getResource())

在这里插入图片描述

try {
	//获取Resource对象中的xml文件流对象
	InputStream inputStream = encodedResource.getResource().getInputStream();
	try {
		//InputSource是jdk中的sax xml文件解析对象
		InputSource inputSource = new InputSource(inputStream);
		if (encodedResource.getEncoding() != null) {
			inputSource.setEncoding(encodedResource.getEncoding());
		}
		//主要看这个方法 **  重要程度 5
		return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
	}
	finally {
		inputStream.close();
	}
}

3.3.9 XmlBeanDefinitionReader#doLoadDocument(inputSource, resource)

  • 根据加载的配置文件把配置文件封装成document对象

在这里插入图片描述

//把inputSource 封装成Document文件对象,这是jdk的API
Document doc = doLoadDocument(inputSource, resource);

//主要看这个方法,根据解析出来的document对象,拿到里面的标签元素封装成BeanDefinition
int count = registerBeanDefinitions(doc, resource);

3.3.10 XmlBeanDefinitionReader#registerBeanDefinitions(doc, resource)

  • 这个document对象就是spring.xml里的内容

在这里插入图片描述
在这里插入图片描述

  • 创建BeanDefinitionDocumentReader对象,DocumentReader负责对document对象解析
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
	//委托模式,BeanDefinitionDocumentReader委托这个类进行document的解析
	BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
	int countBefore = getRegistry().getBeanDefinitionCount();
	//主要看这个方法,createReaderContext(resource) XmlReaderContext上下文,封装了XmlBeanDefinitionReader对象
	documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
	return getRegistry().getBeanDefinitionCount() - countBefore;
}

3.3.11 DefaultBeanDefinitionDocumentReader#registerBeanDefinitions(Document doc, XmlReaderContext readerContext)

  • 把root节点传进去

在这里插入图片描述

3.3.12 DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions(Element root)

在这里插入图片描述

3.3.13 DefaultBeanDefinitionDocumentReader#parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)

  • parseDefaultElement(ele, delegate);负责默认标签解析
  • delegate.parseCustomElement(ele);负责自定义标签解析

在这里插入图片描述

//判断是否是默认的Namespace,http://www.springframework.org/schema/beans
if (delegate.isDefaultNamespace(ele)) {
	//bean标签,走默认标签解析
	parseDefaultElement(ele, delegate);
}
else {
	//自定义标签解析
	delegate.parseCustomElement(ele);
}

在这里插入图片描述

默认标签解析( < bean >)

  • 解析document对象并包装成BeanDefinition对象
  • 解析bean标签内的属性(id,class,scope,primary),并设置到BeanDefinition对象中
  • 再解析bean下面的子标签(lookup-method,replaced-method,property,constructor-arg等)
  • 把BeanDefinition封装成BeanDefinitionHolder对象
  • 对BeanDefinitionHolder对象进行缓存和注册

3.3.13.1 DefaultBeanDefinitionDocumentReader#parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)

在这里插入图片描述

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
	//import标签解析  重要程度 1 
	if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
		importBeanDefinitionResource(ele);
	}
	//alias标签解析 别名标签  重要程度 1
	else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
		processAliasRegistration(ele);
	}
	//bean标签,重要程度 5
	else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
		processBeanDefinition(ele, delegate);
	}
	else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
		// recurse
		doRegisterBeanDefinitions(ele);
	}
}

3.3.13.2 DefaultBeanDefinitionDocumentReader#processBeanDefinition

在这里插入图片描述

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
	//重点看这个方法,重要程度 5 ,解析document,封装成BeanDefinition,再封装成BeanDefinitionHolder对象返回
	BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
	if (bdHolder != null) {

		//装饰者设计模式,加上SPI设计思想,解析namespaceuri方法
		bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
		try {

			//完成document到BeanDefinition对象转换后,对BeanDefinition对象进行缓存注册
			// 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));
	}
}

3.3.13.3 BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element ele)

在这里插入图片描述
在这里插入图片描述

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
	//获取bean标签内的id
	String id = ele.getAttribute(ID_ATTRIBUTE);
	//获取bean标签内的name
	String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
	//获取bean标签内的别名
	List<String> aliases = new ArrayList<>();
	if (StringUtils.hasLength(nameAttr)) {
		String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
		aliases.addAll(Arrays.asList(nameArr));
	}
	//将id赋给beanName
	String beanName = id;
	if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
		beanName = aliases.remove(0);
		if (logger.isTraceEnabled()) {
			logger.trace("No XML 'id' specified - using '" + beanName +
					"' as bean name and " + aliases + " as aliases");
		}
	}

	//检查beanName是否重复
	if (containingBean == null) {
		checkNameUniqueness(beanName, aliases, ele);
	}
	//解析bean,返回beanDefinition对象,重要程度 5
	AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
	if (beanDefinition != null) {
		if (!StringUtils.hasText(beanName)) {
			try {
				if (containingBean != null) {
					beanName = BeanDefinitionReaderUtils.generateBeanName(
							beanDefinition, this.readerContext.getRegistry(), true);
				}
				else {
					beanName = this.readerContext.generateBeanName(beanDefinition);
					// Register an alias for the plain bean class name, if still possible,
					// if the generator returned the class name plus a suffix.
					// This is expected for Spring 1.2/2.0 backwards compatibility.
					String beanClassName = beanDefinition.getBeanClassName();
					if (beanClassName != null &&
							beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
							!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
						aliases.add(beanClassName);
					}
				}
				if (logger.isTraceEnabled()) {
					logger.trace("Neither XML 'id' nor 'name' specified - " +
							"using generated bean name [" + beanName + "]");
				}
			}
			catch (Exception ex) {
				error(ex.getMessage(), ele);
				return null;
			}
		}
		String[] aliasesArray = StringUtils.toStringArray(aliases);
		return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
	}

	return null;
}

3.3.13.4 BeanDefinitionParserDelegate#parseBeanDefinitionElement(ele, beanName, containingBean)

  • 解析bean标签,包装成beanDefinition对象返回

在这里插入图片描述

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对象
		AbstractBeanDefinition bd = createBeanDefinition(className, parent);

		//解析bean标签的属性,并把解析出来的属性设置到BeanDefinition对象中
		parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
		bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

		//解析bean中的meta标签  重要程度:1
		parseMetaElements(ele, bd);

		//解析bean中的lookup-method标签  重要程度:2
		parseLookupOverrideSubElements(ele, bd.getMethodOverrides());

		//解析bean中的replaced-method标签  重要程度:2
		parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

		//解析bean中的constructor-arg标签  重要程度:2
		parseConstructorArgElements(ele, bd);

		//解析bean中的property标签  重要程度:2
		parsePropertyElements(ele, bd);

		//可以不看,用不到
		parseQualifierElements(ele, bd);

		bd.setResource(this.readerContext.getResource());
		bd.setSource(extractSource(ele));
		
		//包装成beanDefinition对象返回
		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;
}

3.3.13.5 回到3.3.13.3步,将beanDefinition封装成BeanDefinitionHolder返回

在这里插入图片描述
在这里插入图片描述

3.3.13.6 回到3.3.13.2步,BeanDefinitionParserDelegate#decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

//根据bean标签属性装饰BeanDefinitionHolder,比如<bean class="xx" p:username="fisher"/>
// Decorate based on custom attributes first.
NamedNodeMap attributes = ele.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
	Node node = attributes.item(i);
	finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}

//根据bean标签子元素装饰BeanDefinitionHolder
// Decorate based on custom nested elements.
NodeList children = ele.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
	Node node = children.item(i);
	if (node.getNodeType() == Node.ELEMENT_NODE) {
		finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
	}
}

3.3.13.7 BeanDefinitionParserDelegate#decorateIfRequired(Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd)

在这里插入图片描述

public BeanDefinitionHolder decorateIfRequired(
		Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {

	//根据node获取到node的命名空间,形如:http://www.springframework.org/schema/p
	String namespaceUri = getNamespaceURI(node);
	if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {

		//这里有SPI服务发现的思想,根据配置文件获取namespaceUri对应的处理类
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
		if (handler != null) {

			//调用NamespaceHandler处理类的decorate方法,开始具体装饰过程,并返回装饰完的对象
			//org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler
			BeanDefinitionHolder decorated =
					handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
			if (decorated != null) {
				return decorated;
			}
		}
		else if (namespaceUri.startsWith("http://www.springframework.org/")) {
			error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
		}
		else {
			// A custom namespace, not to be handled by Spring - maybe "xml:...".
			if (logger.isDebugEnabled()) {
				logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
			}
		}
	}
	return originalDef;
}

3.3.13.8 DefaultNamespaceHandlerResolver#resolve(String namespaceUri)

在这里插入图片描述

public NamespaceHandler resolve(String namespaceUri) {
	//获取spring中所有jar包里面的 "META-INF/spring.handlers"文件,并且建立uri和处理类的映射关系
	Map<String, Object> handlerMappings = getHandlerMappings();

	//根据namespaceUri:http://www.springframework.org/schema/p,获取到这个命名空间的处理类
	Object handlerOrClassName = handlerMappings.get(namespaceUri);
	if (handlerOrClassName == null) {
		return null;
	}
	else if (handlerOrClassName instanceof NamespaceHandler) {
		return (NamespaceHandler) handlerOrClassName;
	}
	else {
		String className = (String) handlerOrClassName;
		try {
			Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
			if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
				throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
						"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
			}
			NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);

			//调用处理类的init方法,在init方法中完成标签元素解析类的注册
			namespaceHandler.init();
			handlerMappings.put(namespaceUri, namespaceHandler);
			return namespaceHandler;
		}
		catch (ClassNotFoundException ex) {
			throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
					"] for namespace [" + namespaceUri + "]", ex);
		}
		catch (LinkageError err) {
			throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
					className + "] for namespace [" + namespaceUri + "]", err);
		}
	}
}

3.3.13.9 DefaultNamespaceHandlerResolver#getHandlerMappings()

在这里插入图片描述

private Map<String, Object> getHandlerMappings() {
	Map<String, Object> handlerMappings = this.handlerMappings;
	if (handlerMappings == null) {
		synchronized (this) {
			handlerMappings = this.handlerMappings;
			if (handlerMappings == null) {
				if (logger.isTraceEnabled()) {
					logger.trace("Loading NamespaceHandler mappings from [" + this.handlerMappingsLocation + "]");
				}
				try {
					//用InputStream流的方式,加载"META-INF/spring.handlers"文件,包装成Properties 对象
					Properties mappings =
							PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
					if (logger.isTraceEnabled()) {
						logger.trace("Loaded NamespaceHandler mappings: " + mappings);
					}

					//所有"META-INF/spring.handlers"文件里面的内容建立映射关系
					handlerMappings = new ConcurrentHashMap<>(mappings.size());
					CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
					this.handlerMappings = handlerMappings;
				}
				catch (IOException ex) {
					throw new IllegalStateException(
							"Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
				}
			}
		}
	}
	return handlerMappings;
}
  • DefaultNamespaceHandlerResolver类中定义了一个常量,文件路径META-INF/spring.handlers

在这里插入图片描述

  • 构造方法,点击this

在这里插入图片描述

  • 赋值操作

在这里插入图片描述

3.3.13.10回到3.3.13.8步,DefaultNamespaceHandlerResolver#resolve(String namespaceUri)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 点开处理类,可以发现所有的处理类都会实现NamespaceHandler接口

在这里插入图片描述

  • 通过反射实例化处理类,并强转为NamespaceHandler

在这里插入图片描述

  • 调用init()方法

在这里插入图片描述

3.3.13.11 回到3.3.13.2 步DefaultBeanDefinitionDocumentReader#registerBeanDefinition(bdHolder, getReaderContext().getRegistry())

  • 完成document到BeanDefinition对象转换后,对BeanDefinition对象进行缓存注册

在这里插入图片描述
在这里插入图片描述

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

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

	//完成BeanDefinition的注册,重点看,重要程度 5
	registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

	//建立别名和 id的映射,这样就可以根据别名获取到id
	// Register aliases for bean name, if any.
	String[] aliases = definitionHolder.getAliases();
	if (aliases != null) {
		for (String alias : aliases) {
			registry.registerAlias(beanName, alias);
		}
	}
}

3.3.13.12 DefaultListableBeanFactory#registerBeanDefinition(String beanName, BeanDefinition beanDefinition)

  • 完成BeanDefinition的注册

在这里插入图片描述

  • beanDefinitionMap
  • beanDefinitionNames存了所有beanDefiniton的名称
//先判断BeanDefinition是否已经注册
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {}

//把beanDefinition缓存到map中
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);

//把beanName放到beanDefinitionNames list中,这个list着重记住,bean实例化的时候需要用到
this.beanDefinitionNames.add(beanName);

3.3.14 DefaultBeanDefinitionDocumentReader#delegate.parseCustomElement(ele)

在这里插入图片描述

自定义标签解析( < context>)

在这里插入图片描述

3.3.14.1 BeanDefinitionParserDelegate#parseCustomElement(Element ele)

在这里插入图片描述

  • 使用xml的方式加载spring的配置文件,启动spring容器

在这里插入图片描述
在这里插入图片描述

3.3.14.2 BeanDefinitionParserDelegate#parse(Element element, ParserContext parserContext)

在这里插入图片描述
在这里插入图片描述

3.3.14.3 BeanDefinitionParserDelegate#findParserForElement(Element element, ParserContext parserContext)

在这里插入图片描述

  • this.parsers.get(localName)为什么能够拿到BeanDefinitionParser对象
  • 通过spring.handlers文件找到namespaceuri(http://www.springframework.org/schema/context)对应的处理类org.springframework.context.config.ContextNamespaceHandler

在这里插入图片描述

  • init方法建立了映射关系

在这里插入图片描述

  • 将ComponentScanBeanDefinitionParser放入map中,对应的key是component-scan

在这里插入图片描述

  • parsers是父类的Map,父类NamespaceHandlerSupport实现NamespaceHandler接口,所以handler才能实现多态

在这里插入图片描述

3.3.14.4 返回parser对象,回到3.3.14.2步,进入ComponentScanBeanDefinitionParser#parse(Element element, ParserContext parserContext)

在这里插入图片描述

  • parser()主要工作
    1、扫描路径.class后缀的文件
    2、要判断类上是否有注解,并封装成metadata对象
    3、genericBeanDefinition.setBeanClass(BeanClass.class)
    4、完成BeanDefinition的注册(beandefinitionNames,beandefinitionMap)

  • 创建注解扫描器

在这里插入图片描述

public BeanDefinition parse(Element element, ParserContext parserContext) {
	//获取basePackage属性
	String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
	basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
	//可以用逗号分开
	String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
			ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

	//创建注解扫描器
	// Actually scan for bean definitions and register them.
	ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
	//扫描并把扫描的类封装成beanDefinition对象  核心方法,重要程度 5
	Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
	registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

	return null;
}

3.3.14.5 ComponentScanBeanDefinitionParser#configureScanner(parserContext, element)

在这里插入图片描述

//使用默认的过滤器
boolean useDefaultFilters = true;
if (element.hasAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)) {
	useDefaultFilters = Boolean.valueOf(element.getAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE));
}

//创建注解的扫描器
// Delegate bean definition registration to scanner class.
ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters);

在这里插入图片描述

3.3.14.6 ClassPathBeanDefinitionScanner#ClassPathBeanDefinitionScanner()构造方法

  • 使用默认的过滤器

在这里插入图片描述

3.3.14.7 ClassPathScanningCandidateComponentProvider#registerDefaultFilters();

在这里插入图片描述

//过滤器中添加需要扫描的注解类型,把@Component注解添加进来
this.includeFilters.add(new AnnotationTypeFilter(Component.class));

在这里插入图片描述

  • Service也添加了@Component注解,所以@Service也能被扫描到

在这里插入图片描述

  • AnnotationTypeFilter用来包装需要扫描的注解的类型

在这里插入图片描述

3.3.14.8 回到3.3.14.5步,ComponentScanBeanDefinitionParser#parseTypeFilters(element, scanner, parserContext);

在这里插入图片描述
在这里插入图片描述

  • 将需要被扫描到的注解和不要被扫描到的注解的类型,分别放到2个集合中

在这里插入图片描述

3.3.14.9 回到3.3.14.4步, ClassPathBeanDefinitionScanner#doScan(String… basePackages)

在这里插入图片描述
在这里插入图片描述

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
	Assert.notEmpty(basePackages, "At least one base package must be specified");
	Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
	for (String basePackage : basePackages) {
		//扫描到有注解的类并封装成BeanDefinition对象
		Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
		for (BeanDefinition candidate : candidates) {
			ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
			candidate.setScope(scopeMetadata.getScopeName());
			String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
			if (candidate instanceof AbstractBeanDefinition) {
				postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
			}
			if (candidate instanceof AnnotatedBeanDefinition) {
				//支持了@Lazy @DependOn注解
				AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
			}
			if (checkCandidate(beanName, candidate)) {
				BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
				//这里不看
				definitionHolder =
						AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
				beanDefinitions.add(definitionHolder);

				//BeanDefinition注册
				registerBeanDefinition(definitionHolder, this.registry);
			}
		}
	}
	return beanDefinitions;
}

3.3.14.10 ClassPathScanningCandidateComponentProvider#findCandidateComponents(String basePackage)

  • componentsIndex一般情况下都为null,所以会走else

在这里插入图片描述

3.3.14.11 ClassPathScanningCandidateComponentProvider#scanCandidateComponents(String basePackage)

在这里插入图片描述

//这里递归寻找文件,所有的.class文件
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);

//扫描类里的信息放在MetadataReader对象中
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
//判断类上面是否有includeFilters集合内包含的注解
if (isCandidateComponent(metadataReader)) {
	//根据MetadataReader 对象内的类的基本信息,包装成BeanDefinition对象
	ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
	sbd.setResource(resource);
	sbd.setSource(resource);
}
  • AnnotationMetadata对象内有类的所有信息,方法、属性、注解等

在这里插入图片描述
在这里插入图片描述

3.3.14.12 回到3.3.14.9步,ClassPathScanningCandidateComponentProvider#registerBeanDefinition(definitionHolder, this.registry)

  • BeanDefinition注册

在这里插入图片描述
在这里插入图片描述

  • 和默认标签解析的注册方法,3.3.13.12步一模一样, DefaultListableBeanFactory#registerBeanDefinition(String beanName, BeanDefinition beanDefinition)

在这里插入图片描述

3.3.14.13 回到3.3.14.9步,ComponentScanBeanDefinitionParser#registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

  • 如果加了@Component的类中,又加了@Autowired、@Value、@Resource、@PostConstruct、@PreDestroy注解,使用这个方法就可以扫描得到
  • 在Bean的实例化过程中有至关重要的作用

在这里插入图片描述

总结

obtainFreshBeanFactory()方法
1、创建XmlBeanDefinitionReader对象
2、Reader通过xml文件路径加载配置文件,转换成Resource对象类型
3、把Resource对象封装成document对象
4、创建BeanDefinitionDocumentReader对象,负责对document对象解析
5、根据namespace判断走默认标签解析还是自定义标签解析
6、parseDefaultElement(ele, delegate);负责常规标签解析
6.1、解析document对象并包装成BeanDefinition对象
6.2、再将BeanDefinition封装成BeanDefinitionHolder返回
6.3、对BeanDefinitionHolder对象进行装饰,解析属性标签或者构造方法标签
6.4、通过SPI加载所有"META-INF/spring.handlers"文件,建立映射关系,找到namespaceUri对应的实现了NamespaceHandler接口的处理类,通过反射实例化处理类,并强转为NamespaceHandler,调用处理类的init方法,完成标签元素解析类的注册;调用NamespaceHandler类的decorate装饰
6.5、registerBeanDefinition对BeanDefinition进行注册,加入到beanDefinitionMap和beanDefinitionNames
7、delegate.parseCustomElement(ele);负责自定义标签解析
7.1、通过SPI找到自定义标签的处理类,调用init方法,完成标签元素解析类的注册,建立标签和解析类的映射关系
7.2、调用ComponentScanBeanDefinitionParser的parse方法,
7.3、创建注解扫描器,使用默认的过滤器,把需要被扫描到的注解和不要被扫描到的注解的类型添加进来
7.4、递归扫描路径下所有.class后缀的文件,把类的信息放在MetadataReader对象中,判断类上面是否包含我需要的注解,封装成BeanDefinition对象
7.5、完成BeanDefinition的注册

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值