【Spring IOC容器简单理解]

Spring 是一款目前主流的 Java EE 轻量级开源框架,可以说的上是JAVA领域最流行,也是开发者们必须要掌握的框架
IOC AOP是Spring核心的两个概念,当然IOC是基础,就是由Spring来负责控制对象的生命周期和对象间的关系,不用通过New方式来创建对象,减少代码之间的耦合


怎样创建一个初始化Spring容器:

public class ApplicationTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        System.err.println( applicationContext.getBean(Demo.class));
    }
}

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:batch="http://www.springframework.org/schema/batch"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/mvc
          http://www.springframework.org/schema/batch
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">

     <context:component-scan base-package="com.dlh.spring.context" />

beans>

【Spring IOC容器简单理解]_第1张图片


这样我们就创建了一个Spring容器,可以看到Demo这个类被Spring管理了,这里的ClassPathXmlApplicationContext 就是Spring容器的实现,接下来我们来了解下这个类

ClassPathXmlApplicationContext 继承体系:

【Spring IOC容器简单理解]_第2张图片
往上继承和实现了不少接口和类,我们来了解下

  1. BeanFactory
    【Spring IOC容器简单理解]_第3张图片

    提供了一些基础的方法,获取bean 、判断容器中是否包含bean、判断bean的Scope模式(单例或者原型)、是否匹配某个类或泛型
    这些接口由子类实现(AbstractApplicationContext 就实现了getBean方法 ,当然具体的实现还是交给了DefaultListableBeanFactory这个才是最终负责Bean的定义实例创建)

  2. HierarchicalBeanFactory

public interface HierarchicalBeanFactory extends BeanFactory {
	BeanFactory getParentBeanFactory();
	boolean containsLocalBean(String name);
}

Hierarchical 层次,这里多提供了两个接口,获取父容器,判断当前容器是否包含bean
3. ListableBeanFactory
【Spring IOC容器简单理解]_第4张图片
正如类名中的List,提供了有关批量获取bean的方法,AbstractApplicationContext也提供了实现

  1. ResourceLoader
public interface ResourceLoader {
	String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;
	Resource getResource(String location);
	ClassLoader getClassLoader();
}

提供了获取Resource的接口,demo里面的spring.xml就是资源,Spring通过解析它创建容器注册Bean定义,前提是我们要找到它

  1. ResourcePatternResolver
public interface ResourcePatternResolver extends ResourceLoader {
	String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
	Resource[] getResources(String locationPattern) throws IOException
}

批量获取接口

  1. DefaultResourceLoader
    默认资源加载实现类

  2. MessageSource
    国际化信息接口

  3. EnvironmentCapable

public interface EnvironmentCapable {
	Environment getEnvironment();
}

提供一个方法获取 Environment ,Environment 在Spring中也是个比较重要的概念,存储了一些配置信息
【Spring IOC容器简单理解]_第5张图片
可以看到Environment实现了PropertyResolver接口,就是解析Property文件来获取配置,AbstractEnvironment有个MutablePropertySources字段来存储当前环境的配置

  1. ApplicationEventPublisher
    事件发布,Spring中的观察者模式,Spring产生事件后执行ApplicationListener监听器onApplicationEvent方法(SimpleApplicationEventMulticaster如果配置了线程池 则监听任务异步执行)
  2. ApplicationContext
    应用程序上下文接口 ,看下前面类的继承关系,这里已经提供不少方法了,但它还是个接口
  3. ConfigurableApplicationContext
    多提供了一些方法 设置环境配置,添加容器后处理器(BeanFactoryPostProcessor),添加监听器,还有个refresh方法(这个是重点)
  4. AbstractApplicationContext
    这是个抽象类,从这里开始已经实现所继承的方法了,可以看到这个类里面有不少变量了
    这个类提供了refresh方法的实现,也就是创建容器,注册bean定义的流程
    另外也实现了一系列getBean的方法
public Object getBean(String name) throws BeansException {
		assertBeanFactoryActive();
		return getBeanFactory().getBean(name);
	}
public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
// 子类AbstractRefreshableConfigApplicationContext 
public final ConfigurableListableBeanFactory getBeanFactory() {
		synchronized (this.beanFactoryMonitor) {
			if (this.beanFactory == null) {
				throw new IllegalStateException("BeanFactory not initialized or already closed - " +
						"call 'refresh' before accessing beans via the ApplicationContext");
			}
			return this.beanFactory;
		}
	}

可以看到getBean具体的逻辑 交给了ConfigurableListableBeanFactory ( 具体是DefaultListableBeanFactory 这个类)

  1. AbstractRefreshableApplicationContext
    这个类多了一个 DefaultListableBeanFactory 变量,是Spring中真正管理Bean的类
  2. AbstractXmlApplicationContext 定义了方法来解析生成bean

DefaultListableBeanFactory:

`前面在介绍ClassPathXmlApplicationContext时候,了解到在实际getBean的时候是委托给DefaultListableBeanFactory来实现的,
ClassPathXmlApplicationContext是应用程序上下文实现类,实现下加载资源,国际化,监听器,后处理器管理,解析注册bean定义等流程上的功能

DefaultListableBeanFactory更加专业 负责bean的注册,实例创建

【Spring IOC容器简单理解]_第6张图片
这是DefaultListableBeanFactory的继承体系,有部分接口在前面有提到过了,我们来看下继承体系中的接口和类的作用

  1. AliasRegistry
public interface AliasRegistry {
	void registerAlias(String name, String alias);
	void removeAlias(String alias);
	boolean isAlias(String name);
	String[] getAliases(String name);
}

别名注册

  1. BeanDefinitionRegistry
public interface BeanDefinitionRegistry extends AliasRegistry {

	void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException;
	void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
	BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
	boolean containsBeanDefinition(String beanName);
	String[] getBeanDefinitionNames();
	int getBeanDefinitionCount();
	boolean isBeanNameInUse(String beanName);
}

接口 定义了BeanDefinition相关的接口

  1. SimpleAliasRegistry
    实现了AliasRegistry 接口别名注册移除的相关功能
  2. SingletonBeanRegistry
    定义了bean 单例实例相关的接口,这里的实例时根据BeanDefinition创建的对象,getBean获取对应的实例
  3. DefaultSingletonBeanRegistry
    bean实例注册实现了,内部有一些变量来存储创建好的bean实例
内部属性 描述
Map singletonObjects 根据BeanDefinition创建好的实例
Map> singletonFactories 创建早期bean的工厂
Map earlySingletonObjects 提前暴露的早期Bean 未完全初始化完成 属性待填充
Set registeredSingletons 缓存已经实例化的bean的名称
Set singletonsCurrentlyInCreation 正在创建的bean
Map dependentBeanMap Key值代表的Bean被其他多少bean依赖
Map dependenciesForBeanMap Key值代表的Bean依赖其它多少Bean
  1. FactoryBeanRegistrySupport
    支持FactoryBean的创建 ,FactoryBean是容器中Bean的类型的一种,FactoryBean通过getObject方法获取对象
  2. ConfigurableBeanFactory
    定义了一些接口来添加Spring容器中需要的工具类
方法 描述
setBeanExpressionResolver 设置SpringEL表达式解析器 容器refresh过程中设置 StandardBeanExpressionResolver
setConversionService 设置一个ConversionService属性转换器,容器refresh过程中设置默认是FormattingConversionService
addPropertyEditorRegistrar 添加一个PropertyEditorRegistrar (向容器中注册PropertyEditorRegistry),PropertyEditorRegistry可向容器中添加属性编辑器PropertyEditor 容器refresh过程中向Spring添加了一个ResourceEditorRegistrar
registerCustomEditor 注册一个属性编辑器实现类
setTypeConverter 添加一个类型转换接口
addBeanPostProcessor Spring容器中注册的BeanDefinition 对应Class如果实现了BeanPostProcessor将其添加到Spring容器中
addEmbeddedValueResolver 添加一个StringValueResolver接口,StringValueResolver 实现类用了解析Spring配置文件中的占位符比如${name}
  1. AbstractBeanFactory
    提供了跟Bean 相关方法的顶层实现,维护了一些工具类信息
  2. AutowireCapableBeanFactory
    定义了自动装配的方法实现,注意下接口的createBean方法, AbstractBeanFactory创建Bean的过程中会调用到这里
  3. AbstractAutowireCapableBeanFactory
    实现了bean装配,实例属性填充等方法
  4. ConfigurableListableBeanFactory
    在继承体系之上添加了几个接口方法
方法 描述
ignoreDependencyType 忽略自动装配的类
ignoreDependencyInterface 忽略自动装配的接口
isAutowireCandidate 判断指定的Bean是否有资格作为自动装配的目标对象
preInstantiateSingletons 实例化所有非延迟加载单例类
  1. DefaultListableBeanFactory
    Bean工厂的默认实现

Spring 容器refresh流程 :

关于IOC容器个人理解有两个容器,一个是应用程序上下文实现类(外层容器设置 内层容器注册BeanDefinition获取bean实例所需的资源),内层容器DefaultListableBeanFactory 只负责bean注册 实例创建相关的逻辑

接下来我们看看Spring容器的refresh流程 ,这个方法是在AbstractApplicationContext 里面

	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// 子类实现初始化环境上下文信息Environment 
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
		    // 创建容器并向容器中注册BeanDefinition
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
		        /**
				 * 设置EL表达式解析器
				 * 添加处理Aware回调接口的Bean处理器
				 * 忽略给定接口的字段装配功能
				 * BeanFactory ResourceLoader ApplicationEventPublisher ApplicationContext注册ResolvableDependency(就是指定该类型接口,如果外部要注入该类型接口的对象,则会注入我们指定的对象,而不会去管其他接口实现类)
				 * 注册ApplicationListenerDetector 实现了Bean后处理器接口,如果对应bean是ApplicationListener实例,销毁bean时移除监听器
				 */

				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				/**
				 * 初始化容器后处理器
				 * 先调用实现BeanDefinitionRegistryPostProcessor接口容器后处理器类的postProcessBeanDefinitionRegistry方法
				 * 再调用实现BeanFactoryPostProcessor接口容器后处理器类的postProcessBeanFactory方法
				 */

				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				/**
				 * 容器中注册的Bean对应的Class如果实现了BeanPostProcessor,对应Class添加到Spring容器
				 */
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				// 设置容器中的事件广播类 ,没有定义相关Bean则默认值是SimpleApplicationEventMulticaster
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				// 子类扩展 SpringBoot 应用程序上下文ServletWebServerApplicationContext实现onRefresh方法创建了一个WebServer来监听端口
				onRefresh();

				// Check for listener beans and register them.
				// 监听器添加到ApplicationEventMulticaster
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				// 容器初始化完成初始化容器中的所有单例bean,如果bean继承了SmartInitializingSingleton接口同时调用afterSingletonsInstantiated方法
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				// 设置容器中的LifecycleProcessor  onRefresh 
				// 发布ContextRefreshedEvent实际 DispatcherServlet父类FrameworkServlet监听到这个事件初始化MVC相关组件
				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();
			}
		}
	}

BeanDefinition 注册流程 :

registerBeanPostProcessors方法会在Spring容器中查找BeanDefinition 对应的class是实现了BeanPostProcessor接口的bean,也就是在这之前已经将BeanDefinition 注册到容器当中了,具体是在obtainFreshBeanFactory创建容器后加载资源文件来解析bean的,我们来看下具体流程(以ClassPathXmlApplicationContext 创建为例子)

  1. AbstractRefreshableApplicationContext loadBeanDefinitions方法,这里是注册BeanDefinition 的开始
protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
			loadBeanDefinitions(beanFactory);
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}
  1. loadBeanDefinitions 具体实现在AbstractXmlApplicationContext类中,创建了一个XmlBeanDefinitionReader对象来读取xml配置文件来解析bean
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
		beanDefinitionReader.setEnvironment(this.getEnvironment());
		beanDefinitionReader.setResourceLoader(this);
		// ResourceEntityResolver 有一个ResourceLoader定义了加载资源的方法,AbstractXmlApplicationContext就继承了这个接口
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
		initBeanDefinitionReader(beanDefinitionReader);
		loadBeanDefinitions(beanDefinitionReader);
	}

从两个路径下获取资源再调用XmlBeanDefinitionReader loadBeanDefinitions方法

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
		Resource[] configResources = getConfigResources();
		if (configResources != null) {
			reader.loadBeanDefinitions(configResources);
		}
		// new ClassPathXmlApplicationContext("spring.xml") 这种构造方式configLocations 有值
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			reader.loadBeanDefinitions(configLocations);
		}
	}

拿到资源文件路径开开始解析,父类AbstractBeanDefinitionReader循环读取资源路径下的配置文件来解析BeanDefinition

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

将资源文件路径转化为Resource ResourcePatternResolver匹配到多个Resource ,获取资源后调用到BeanDefinitionReader loadBeanDefinitions (这里类里面有几个这样的加载bean定义的方法 入参不同,这里传的参数是Resource )

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.
			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;
		}
	}

调用到XmlBeanDefinitionReader doLoadBeanDefinitions

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.add(encodedResource)) {
			throw new BeanDefinitionStoreException(
					"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
		}

		try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
			InputSource inputSource = new InputSource(inputStream);
			if (encodedResource.getEncoding() != null) {
				inputSource.setEncoding(encodedResource.getEncoding());
			}
			return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException(
					"IOException parsing XML document from " + encodedResource.getResource(), ex);
		}
		finally {
			currentResources.remove(encodedResource);
			if (currentResources.isEmpty()) {
				this.resourcesCurrentlyBeingLoaded.remove();
			}
		}
	}

解析资源文件成Document调用registerBeanDefinitions 注册bean定义

//省略try catch
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
Document doc = doLoadDocument(inputSource, resource);
			int count = registerBeanDefinitions(doc, resource);
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + count + " bean definitions from " + resource);
			}
			return count;
	}
  1. XmlBeanDefinitionReader registerBeanDefinitions方法创建BeanDefinitionDocumentReader解析注册bean定义

BeanDefinitionDocumentReader 有一个XmlReaderContext变量 ,XmlReaderContext 内部又有个NamespaceHandlerResolver
定义了不同命名空间的bean解析器
createReaderContext 创建了XmlReaderContext 对象跟踪代码到最后发现是读取了META-INF/spring.handlers配置
【Spring IOC容器简单理解]_第7张图片

	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
	    //默认是DefaultBeanDefinitionDocumentReader
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		int countBefore = getRegistry().getBeanDefinitionCount();
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}
  1. DefaultBeanDefinitionDocumentReader doRegisterBeanDefinitions方法解析文档注册bean定义实现逻辑在parseBeanDefinitions方法里面
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		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);
		}
	}

上面解析的代码,有几个条件分支,实际只有两种情况,调用parseDefaultElement 或者
BeanDefinitionParserDelegate的parseCustomElement方法


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:batch="http://www.springframework.org/schema/batch"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/mvc
          http://www.springframework.org/schema/batch
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">
     <bean id="interFace" class="com.dlh.spring.context.InterFaceImpl"/>
     <context:component-scan base-package="com.dlh.spring.context" />
     <bean id="beanNameAutoProxy"  class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
          <property name="beanNames" value="interFace" />
          <property name="interceptorNames">
               <list>
                    <value>myMethodInterceptorvalue>
               list>
          property>
     bean>
     <bean id="myMethodInterceptor" class="com.dlh.spring.context.MyMethodInterceptor"/>
beans>

我们解析的spring配置文件长这样,解析成DOM元素
【Spring IOC容器简单理解]_第8张图片
满足parseBeanDefinitions方法的外层if条件,里面的if节点 是循环解析解析整个DOM的子节点

 <bean id="interFace" class="com.dlh.spring.context.InterFaceImpl"/>```
 <context:component-scan base-package="com.dlh.spring.context" />```

这里
【Spring IOC容器简单理解]_第9张图片
所以当解析 component-scan 节点时调用的是BeanDefinitionParserDelegate的parseCustomElement方法
看这个类名当中的意思我们已经能猜到是将bean解析交给其它类来处理,具体来看下代码

public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
		String namespaceUri = getNamespaceURI(ele);
		if (namespaceUri == null) {
			return null;
		}
		// 这里实现类是DefaultNamespaceHandlerResolver ,handlerMappings 保存了namespaceUri  跟 NamespaceHandler 的映射关系
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
		if (handler == null) {
			error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
			return null;
		}
		// 调用NamespaceHandler 接口子类parse方法解析
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
	}

这个方法的逻辑就是根据节点的namespaceUri 找到对应的命名空间解析器,再调用具体解析器的parse方法(parse之前会先调用NamespaceHandler init方法)注册Bean到容器
也就是 namespaceURI 是http://www.springframework.org/schema/beans的节点 ,其它类型的节点都要有对应的命名空间处理器 NamespaceHandler
【Spring IOC容器简单理解]_第10张图片
其它框架与Spring继承也会实现NamespaceHandler 接口来解析配置文件

我们再回头看看parseBeanDefinitions的另外一种情况,就是namespaceURI 是http://www.springframework.org/schema/beans的节点,会调用parseDefaultElement 方法

if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			doRegisterBeanDefinitions(ele);
		}

这里有针对nodeName(也就是子节点bean context这样的节点标识)四种情况

nodeName 处理逻辑
import 重新导入一个资源文件解析 这个节点有一个Resource属性代表资源文件路径
alias 注册一些bean的别名
beans 重新再走向doRegisterBeanDefinitions 流程 beans子节点才是真正要解析的数据
bean 这个就代表Spring容器中的一个bean了具体的解析过程都在BeanDefinitionParserDelegate

你可能感兴趣的:(Spring,JAVA基础,spring,java,spring,boot)