Spring源码分析(六)

15 篇文章 0 订阅

Spring源码分析

第五章 Spring Ioc的初始化


前言

这一章,我们主要分析一下 Spring Ioc的初始化详细流程,在分析详细流程之前,简单了解一下spring Ioc的容器体系及Spring Bean的生命周期


一、Spring IoC的容器体系

IoC容器是Spring的核心模块,是抽象了对象管理、依赖关系管理的框架解决⽅案。Spring 提供了很多 的容器,其中BeanFactory 是顶层容器(根容器),不能被实例化,它定义了所有 IoC 容器 必须遵从的⼀套原则,具体的容器实现可以增加额外的功能,比如我们常⽤到的ApplicationContext,其下更具 体的实现如ClassPathXmlApplicationContext 包含了解析 xml 等⼀系列的内容,AnnotationConfigApplicationContext 则是包含了注解解析等⼀系列的内容。Spring IoC 容器继承体系⾮常聪明,需要使⽤哪个层次⽤哪个层次即可,不必使⽤功能⼤而全的。

BeanfFactory顶级接⼝方法栈如下:
在这里插入图片描述
BeanFactory 容器继承体系:
在这里插入图片描述

通过其接⼝设计,我们可以看到我们⼀贯使⽤的 ApplicationContext
除了继承BeanFactory的⼦接⼝,还继承了ResourceLoader、MessageSource等接⼝,因此其提供的功能也就更丰富了。

二、Spring Bean的生命周期

在这里插入图片描述

  1. SpringBean进行实例化(相当于程序中的new Xx()
  2. Spring将值和Bean的引用注入进Bean对应的属性中
  3. 如果Bean实现了BeanNameAware接口,SpringBeanID传递给setBeanName()方法(实现BeanNameAware主要是为了通过Bean的引用来获得BeanID,一般业务中是很少有用到BeanID的)
  4. 如果Bean实现了BeanFactoryAware接口,Spring将调用setBeanDactory(BeanFactory bf)方法并把BeanFactory容器实例作为参数传入。(实现BeanFactoryAware 主要目的是为了获取Spring容器,如Bean通过Spring容器发布事件等)
  5. 如果Bean实现了ApplicationContextAwaer接口,Spring容器将调用setApplicationContext(ApplicationContext ctx)方法,把y应用上下文作为参数传入.(作用与BeanFactory类似都是为了获取Spring容器,不同的是Spring容器在调用setApplicationContext方法时会把它自己作为setApplicationContext 的参数传入,而Spring容器在调用setBeanDactory前需要程序员自己指定(注入)setBeanFactory里的参数BeanFactory )
  6. 如果Bean实现了BeanPostProcess接口,Spring将调用它们的postProcessBeforeInitialization(预初始化)方法(作用是在Bean实例创建成功后对进行增强处理,如对Bean进行修改,增加某个功能)
  7. 如果Bean实现了InitializingBean接口,Spring将调用它们的afterPropertiesSet方法,作用与在配置文件中对Bean使用init-method声明初始化的作用一样,都是在Bean的全部属性设置成功后执行的初始化方法。
  8. 如果Bean实现了BeanPostProcess接口,Spring将调用它们的postProcessAfterInitialization(后初始化)方法(作用与6的一样,只不过6是在Bean初始化前执行的,而这个是在Bean初始化后执行的,时机不同 )
  9. 经过以上的工作后,Bean将一直驻留在应用上下文中给应用使用,直到应用上下文被销毁
  10. 如果Bean实现了DispostbleBean接口,Spring将调用它的destory方法,作用与在配置文件中对Bean使用destory-method属性的作用一样,都是在Bean实例销毁前执行的方法。

三、Spring Ioc的初始化过程

相信大家对这段代码都很熟悉:

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
LagouBean lagouBean = applicationContext.getBean(LagouBean.class);
System.out.println(lagouBean);

上面代码中,在创建ApplicationContext实例对象过程中会创建一个spring容器,该容器会读取配置文件cjj/models/beans.xml,并统一管理由该文件中定义好的所有bean实例对象,如果要获取某个bean实例,使用getBean方法就行了。
回到正题上来,关于Spirng IoC容器的初始化过程在《Spirng技术内幕:深入解析Spring架构与设计原理》一书中有明确的指出,IoC容器的初始化过程可以分为三步:

  1. Resource定位(Bean的定义文件定位)
  2. Resource定位好的资源载入到BeanDefinition
  3. BeanDefiniton注册到容器中

下面就通过源码分析来具体研究一下Spirng IoC容器的初始化过程。

四、Spring Ioc的初始化过程详解

启动一下测试代码:

public void testIoC() {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
		LagouBean lagouBean = applicationContext.getBean(LagouBean.class);
		System.out.println(lagouBean);
}

可以看到程序进入:

ClassPathXmlApplicationContext.java
	//创建一个新的ClassPathXmlApplicationContext,加载定义
	public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
		this(new String[] {configLocation}, true, null);
	}

// 继续执行
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)throws BeansException {
	// 初始化父类
	super(parent);
	// 设置本地的配置信息
	setConfigLocations(configLocations);
	// 初始化操作
	if (refresh) {
		refresh();
	}
}

点击进入refresh方法当中:

	public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            //刷新前的预处理;
            prepareRefresh();

            //获取BeanFactory;默认实现是DefaultListableBeanFactory,在创建容器的时候创建的
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            //BeanFactory的预准备工作(BeanFactory进行一些设置,比如context的类加载器,BeanPostProcessor和XXXAware自动装配等)
            prepareBeanFactory(beanFactory);

            try {
                //BeanFactory准备工作完成后进行的后置处理工作
                postProcessBeanFactory(beanFactory);

                //执行BeanFactoryPostProcessor的方法;
                invokeBeanFactoryPostProcessors(beanFactory);

                //注册BeanPostProcessor(Bean的后置处理器),在创建bean的前后等执行
                registerBeanPostProcessors(beanFactory);

                //初始化MessageSource组件(做国际化功能;消息绑定,消息解析);
                initMessageSource();

                //初始化事件派发器
                initApplicationEventMulticaster();

                //子类重写这个方法,在容器刷新的时候可以自定义逻辑;如创建Tomcat,Jetty等WEB服务器
                onRefresh();

                //注册应用的监听器。就是注册实现了ApplicationListener接口的监听器bean,这些监听器是注册到ApplicationEventMulticaster中的
                registerListeners();

                //初始化所有剩下的非懒加载的单例bean
                finishBeanFactoryInitialization(beanFactory);

                //完成context的刷新。主要是调用LifecycleProcessor的onRefresh()方法,并且发布事件(ContextRefreshedEvent)
                finishRefresh();
            }
            ......
    }

可以看得出来,spring容器的启动,创建bean,bean的初始化等一系列过程都在这个refresh方法里面进行调用。我们先来看下这段代码:

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

这段代码,主要是用于获取BeanFactory,默认实现是DefaultListableBeanFactory,我们点击进入看下实现:

AbstractApplicationContext.java
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
	refreshBeanFactory();
	return getBeanFactory();
}

可以猜到,getBeanFactory()方法应该是获取ConfigurableListableBeanFactory 对象的一个方法,在这之前BeanFactory应该已经完成创建,所以我们进入refreshBeanFactory()方法,了解一下该方法的具体实现:

@Override
protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			// 实例化DefaultListableBeanFactory
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			// 设置序列化Id
			beanFactory.setSerializationId(getId());
			// 自定义bean工厂的一些属性(是否允许覆盖 循环依赖)
			customizeBeanFactory(beanFactory);
			// 加载应用中的BeanDefinitions
			loadBeanDefinitions(beanFactory);
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

简单解释下这段代码:

if (hasBeanFactory()) {
	destroyBeans();
	closeBeanFactory();
}

这一小段代码主要是用于判断是否已经存在一个BeanFactory,若果要是存在就将其销毁然后关闭;可以简单看下hasBeanFactory()方法:

AbstractApplicationContext.java

protected final boolean hasBeanFactory() {
	synchronized (this.beanFactoryMonitor) {
		return (this.beanFactory != null);
	}
}

接下来,我们来看下try...catch...代码块里面的内容:

// 实例化DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 设置序列化Id
beanFactory.setSerializationId(getId());
// 自定义bean工厂的一些属性(是否允许覆盖 循环依赖)
customizeBeanFactory(beanFactory);
// 加载应用中的BeanDefinitions
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
	this.beanFactory = beanFactory;
}

DefaultListableBeanFactorybean加载的核心部分,是Spring注册及加载的默认实现。先来看下DefaultListableBeanFactory的类图:
在这里插入图片描述
先概述接口部分:

  1. BeanFactorySpring的最根的接口,类的工厂接口。
  2. HierarchicalBeanFactory接口是在继承BeanFactory的基础上,实现BeanFactory的父子关系。
  3. AutowireCapableBeanFactory接口是在继承BeanFactory的基础上,实现Bean的自动装配功能
  4. ListableBeanFactory接口是在继承BeanFactory的基础上,实现Beanlist集合操作功能
  5. ConfigurableBeanFactory接口是在继承HierarchicalBeanFactory的基础上,实现BeanFactory的全部配置管理功能, SingletonBeanRegistry是单例bean的注册接口
  6. ConfigurableListableBeanFactory接口是继承AutowireCapableBeanFactoryListableBeanFactoryConfigurableBeanFactory三个接口的一个综合接口

再概述类部分:

  1. AliasRegistry接口是别名注册接口,SimpleAliasRegistry类是简单的实现别名注册接口的类。
  2. DefaultSingletonBeanRegistry是默认的实现SingletonBeanRegistry接口的类,同时,继承类SimpleAliasRegistry
  3. FactoryBeanRegistrySupport是实现FactoryBean注册的功能实现。继承类DefaultSingletonBeanRegistry
  4. AbstractBeanFactory是部分实现接口ConfigurableBeanFactory,并继承类FactoryBeanRegistrySupport
  5. AbstractAutowireCapableBeanFactory是实现接口AutowireCapableBeanFactory,并继承类 AbstractBeanFactory
  6. DefaultListableBeanFactory实现接口 ConfigurableListableBeanFactoryBeanDefinitionRegistrybean定义的注册接口), 并继承AbstractAutowireCapableBeanFactory,实现全部类管理的功能。

DefaultListableBeanFactory其实要实现的功能就是以list集合的方式操作bean,为什么要拆成这么多的类和接口呢。这里面可能基于几点考虑。

  1. 功能的不同维度,分不同的接口,方便以后的维护和其他人的阅读。如:AutowireCapableBeanFactoryListableBeanFactoryHierarchicalBeanFactory
  2. 不同接口的实现,分布在不同的之类里,方便以后不同接口多种实现的扩展
  3. 从整个类图的分布,可以看出spring在这块是面向接口编程,后面类的实现,他们认为只是接口功能实现的一种,随时可以拓展成多种实现以拓展成多种实现

最后来说下DefaultListableBeanFactory 的内部都维护了一些什么:

/** Optional id for this factory, for serialization purposes. */
	@Nullable
	private String serializationId;

	/** Whether to allow re-registration of a different definition with the same name. */
	private boolean allowBeanDefinitionOverriding = true;

	/** Whether to allow eager class loading even for lazy-init beans. */
	private boolean allowEagerClassLoading = true;

	/** Optional OrderComparator for dependency Lists and arrays. */
	@Nullable
	private Comparator<Object> dependencyComparator;

	/** Resolver to use for checking if a bean definition is an autowire candidate. */
	private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();

	/** Map from dependency type to corresponding autowired value. */
	private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);

	/** Map of bean definition objects, keyed by bean name. */
	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

	/** Map of singleton and non-singleton bean names, keyed by dependency type. */
	private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);

	/** Map of singleton-only bean names, keyed by dependency type. */
	private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64);

	/** List of bean definition names, in registration order. */
	private volatile List<String> beanDefinitionNames = new ArrayList<>(256);

	/** List of names of manually registered singletons, in registration order. */
	private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16);

	/** Cached array of bean definition names in case of frozen configuration. */
	@Nullable
	private volatile String[] frozenBeanDefinitionNames;

	/** Whether bean definition metadata may be cached for all beans. */
	private volatile boolean configurationFrozen = false;

可以看到,DefaultListableBeanFactory 内部维护了超级多的一些东西。我们主要关注两个属性:

// BeanDefinition 的存储 Map 其中 key 为 beanName 
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256); 

// BeanName 的集合 
private volatile List<String> beanDefinitionNames = new ArrayList<>(256); 

正如注释所说,DefaultListableBeanFactory 内部维护了一个ConcurrentHashMap,用于存储 beanNameBeanDefinition的映射关系。
简单了解了DefaultListableBeanFactory之后,我们回到org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory继续往下走:

// 设置序列化Id
beanFactory.setSerializationId(getId());
// 自定义bean工厂的一些属性(是否允许覆盖 循环依赖)
customizeBeanFactory(beanFactory);

这两行代码,一个是设置序列化相关的序列化ID,另一个定义了bean工厂的一些自定义属性,类似循环依赖,关于循环依赖暂时不做详细说明,放到下一节讨论,我们继续向下:

// 加载应用中的BeanDefinitions
loadBeanDefinitions(beanFactory);

这段代码用于加载应用中的BeanDefinitions,我们来看下具体实现:

AbstractXmlApplicationContext.java

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
	// 给指定的BeanFactory创建一个XmlBeanDefinitionReader读取器对象,用于解析xml对象
	XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

	// 设置一些context应用上下文的环境属性
	beanDefinitionReader.setEnvironment(this.getEnvironment());
	beanDefinitionReader.setResourceLoader(this);
	beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

	// 为子类实现提供一些自定义的初始化策略
	initBeanDefinitionReader(beanDefinitionReader);
	// 加载BeanDefinitions
	loadBeanDefinitions(beanDefinitionReader);
}

我们直接看最后一段代码

loadBeanDefinitions(beanDefinitionReader);

AbstractBeanDefinitionReader类中loadBeanDefinitions方法,使用beanDefinitionReader解析xmlbeanDefinition并填充到IOC容器中,我们来看下具体实现:

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
		// 从Resource资源对象加载BeanDefinitions
		Resource[] configResources = getConfigResources();
		if (configResources != null) {
			//当ApplicationContext的入参是一个Resource对象的时候 走这个流程
			//核心方法 BeanDefinitionReader 开始加载解析beanDefinitions
			reader.loadBeanDefinitions(configResources);
		}
		// 从xml配置文件加载BeanDefinitions
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			//当ApplicationContext的入参是一个String形式的字符串路径的时候 走这个流程
			//核心方法 BeanDefinitionReader 开始加载解析beanDefinitions
			reader.loadBeanDefinitions(configLocations);
		}
	}

然后我们再来看下reader.loadBeanDefinitions(configLocations)的具体实现:

AbstractBeanDefinitionReader.java

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

这段代码中的for循环实际上就是循环加载配置文件,并把加载了多少个返回回去,我们继续向下进行,看一下loadBeanDefinitions(location)方法是如何加载配置文件的:

AbstractBeanDefinitionReader.java
@Override
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
	return loadBeanDefinitions(location, null);
}

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
			Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
			// 加载配置中的eanDefinitions对象 并返回数量
			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;
	}
}

这一段没什么特殊的,我们点击进入 loadBeanDefinitions(resources);方法:

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

似曾相识的一个方法,只不过循环的东西不一样,刚刚的是xml,这次循环加载的是Resource;我们点击进入loadBeanDefinitions(resource)方法中:

XmlBeanDefinitionReader.java
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
	return loadBeanDefinitions(new EncodedResource(resource));
}

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

这一段进行了一些校验,并把xml文件流封装为InputSource对象;然后进入doLoadBeanDefinitions(inputSource, encodedResource.getResource());方法中,该方法执行了具体的加载逻辑;

XmlBeanDefinitionReader.java
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
		throws BeanDefinitionStoreException {

	try {
		//读取XML信息,并将Xml信息保存到Document 对象中
		Document doc = doLoadDocument(inputSource, resource);
		//解析Document,封装BeanDefinitions并进行注册
		int count = registerBeanDefinitions(doc, resource);
		if (logger.isDebugEnabled()) {
			logger.debug("Loaded " + count + " bean definitions from " + resource);
		}
		return count;
	}
	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);
	}
}

到这一步,解析XML基本完成。这一段代码主要进行了BeanDefinitions的封装及注册,具体逻辑在registerBeanDefinitions(doc, resource)方法当中,我们看一下这个方法的实现:

XmlBeanDefinitionReader.java

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
	// 定义BeanDefinitionDocumentReader 对象,用于处理传入的Document对象
	BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
	// 获取已有的BeanDefinition对象数量
	int countBefore = getRegistry().getBeanDefinitionCount();
	// 注册BeanDefinition
	documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
	// 返回新注册的BeanDefinition数量
	return getRegistry().getBeanDefinitionCount() - countBefore;
}

getRegistry().getBeanDefinitionCount();这个方法实际上就是从一个Map中获取已经注册了多少个BeanDefinition对象;新注册的BeanDefinition也会放在这个集合中
我们主要关注如何注册的,所以点击进入documentReader.registerBeanDefinitions(doc, createReaderContext(resource));方法,看一下他的实现:

DefaultBeanDefinitionDocumentReader.java
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
	this.readerContext = readerContext;
	doRegisterBeanDefinitions(doc.getDocumentElement());
}


protected void doRegisterBeanDefinitions(Element root) {
	// 定义一个有状态的委托类,用来解析Xml中bean的定义
	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;
			}
		}
	}
	//解析前的处理,DefaultBeanDefinitionDocumentReader没有实现它,子类可以实现,来扩展功能
	preProcessXml(root);
	 // 解析root内的XML标签,如<import> <alias> <bean>等
	parseBeanDefinitions(root, this.delegate);
	// 解析后的处理,同样没有实现它,子类可以实现。
	postProcessXml(root);

	this.delegate = parent;
}

然后我们再来看下具体的解析方法:parseBeanDefinitions(root, this.delegate)方法

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

这一段代码循环去处理解析对应的标签(默认标签和自定义标签),我们看下默认标签是如何解析的:

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
	// import 元素处理
	if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
		importBeanDefinitionResource(ele);
	}
	// alias元素处理
	else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
		processAliasRegistration(ele);
	}
	// bean元素处理
	else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
		processBeanDefinition(ele, delegate);
	}
	// 嵌套beans处理
	else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
		// recurse
		doRegisterBeanDefinitions(ele);
	}
}

主要看下bean元素处理:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
	// 解析bean元素为BeanDefinition,但是此时使用BeanDefinitionHolder,实际上BeanDefinitionHolder就已经持有了一个BeanDefinition
	BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
	if (bdHolder != null) {
		// 处理自定义标签
		bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
		try {
		// 完成BeanDefinition注册
		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(bdHolder, getReaderContext().getRegistry());

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

	// 获取beanName
	String beanName = definitionHolder.getBeanName();
	// 注册
	registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

	// 获取别名
	String[] aliases = definitionHolder.getAliases();
	if (aliases != null) {
		for (String alias : aliases) {
			// 存储别名
			registry.registerAlias(beanName, alias);
		}
	}
}

继续向下,进入registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());方法:

DefaultListableBeanFactory.java
@Override
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) {
		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 + "]");
			}
		}
		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;
				removeManualSingletonName(beanName);
			}
		}
		else {
			// 放入beanDefinitionMap 也就是注册
			this.beanDefinitionMap.put(beanName, beanDefinition);
			this.beanDefinitionNames.add(beanName);
			removeManualSingletonName(beanName);
		}
		this.frozenBeanDefinitionNames = null;
	}

	if (existingDefinition != null || containsSingleton(beanName)) {
		resetBeanDefinition(beanName);
	}
}

到此为止,就完成了xml的解析->BeanDefinition->注册的一个全流程

系列连接

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值