Spring Bean加载过程(源码解读)

BeanFactory与ApplicationContext区别

BeanFactory是ApplicationContext的一个子集,BeanFactory只提供简单容器的功能,就像只有一个水桶,水桶里面只装了水。(水桶就像beanFactory,水就是bean)。ApplicationContext除了有容器功能以外,还提供了国际化,事件监听等,就像水桶了除了装了水,还有鱼,虾。

Spring Bean加载过程

言归正传,看bean的加载过程。我们只要选一个BeanFactory(单纯的水桶)作为例子来讲解,来看看水桶是怎么一步一步装水的。

测试代码:
/**
 * <pre>类名: ApplicationContextTest</pre>
 * <pre>描述: 应用上下文测试</pre>
 * <pre>版权: web_chen@163.com</pre>
 * <pre>日期: 2020/10/15 9:16</pre>
 * <pre>作者: chenwb</pre>
 */
public class ApplicationContextTest {

    public static void main(String[] args) {
        XmlBeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("/XmlConfig.xml"));
        System.out.println(((User)xmlBeanFactory.getBean("user")).getName());
    }
}

XmlConfig.xml,就是一个简单的user Bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<bean id="user" class="ioc.User">
		<property name="name" value="Jerry"/>
	</bean>
</beans>

执行结果就是打印一次Jerry

十月 15, 2020 9:33:54 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [XmlConfig.xml]
Jerry
进入XmlBeanFactory:

它继承了DefaultListableBeanFactory,这是一个最常见的bean工厂实现。XmlBeanFactory内容很少,只有一个专门针对XML配置读取的XmlBeanDefinitionReader,XmlBeanDefinitionReader负责读取XML的Bean定义

public class XmlBeanFactory extends DefaultListableBeanFactory {

	private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
	
	public XmlBeanFactory(Resource resource) throws BeansException {
		this(resource, null);
	}
	public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
		super(parentBeanFactory);
		this.reader.loadBeanDefinitions(resource);
	}
}

在DefaultListableBeanFactory中,主要有一个ConcurrentHashMap用来beanDefinition的定义(因为我们这次只管Bean的加载,就只管beanDefinition吧):

	/** Map of bean definition objects, keyed by bean name */
	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);
我们开始载入bean,XmlBeanDefinitionReader.loadBeanDefinitions(Resource resource):
	@Override
	public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
		return loadBeanDefinitions(new EncodedResource(resource));
	}
	
	// 进行BeanDefinitions载入
	public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		// resourcesCurrentlyBeingLoaded是一个ThreadLocal,用来记录当前正在载入的资源(主要是为并发场景考虑的,但我们这里没有并发)
		Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
		if (currentResources == null) {
			currentResources = new HashSet<EncodedResource>(4);
			this.resourcesCurrentlyBeingLoaded.set(currentResources);
		}
		// 并发场景重复载入资源时报错
		if (!currentResources.add(encodedResource)) {
			throw new BeanDefinitionStoreException(
					"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
		}
		try {
			// 将encodedResource转为InputStream,再转为InputSource 
			InputStream inputStream = encodedResource.getResource().getInputStream();
			try {
				InputSource inputSource = new InputSource(inputStream);
				if (encodedResource.getEncoding() != null) {
					inputSource.setEncoding(encodedResource.getEncoding());
				}
				// 真正开始加载bean定义
				return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
			}
			finally {
				inputStream.close();
			}
		}
		finally {
			currentResources.remove(encodedResource);
			if (currentResources.isEmpty()) {
				// threadLocal用完之后移除
				this.resourcesCurrentlyBeingLoaded.remove();
			}
		}
	}
	
	// 前面资源格式进行了转换,接下来进行“真家伙”了
	protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
		try {
			// 加载Document
			Document doc = doLoadDocument(inputSource, resource);
			// 根据Document注册Bean
			return registerBeanDefinitions(doc, resource);
		}
		...省略异常捕获
	}
接下来就是doLoadDocument与registerBeanDefinitions了,就是一个取水,并将水加入水桶一样:

先看doLoadDocument,默认使用的是DefaultDocumentLoader:

	protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
		return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
				getValidationModeForResource(resource), isNamespaceAware());
	}
	
	/**
	 * Load the {@link Document} at the supplied {@link InputSource} using the standard JAXP-configured
	 * XML parser.
	 */
	@Override
	public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
			ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
		// 创建构建工厂
		DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
		// 获取构造器
		DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
		// 生成Document
		return builder.parse(inputSource);
	}

再看registerBeanDefinitions:

	// 返回的是本次注册的bean定义数量
	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		// BeanDefinitionDocumentReader 采用的是DefaultBeanDefinitionDocumentReader,不过这里采用的是反射,见下面
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		documentReader.setEnvironment(getEnvironment());
		int countBefore = getRegistry().getBeanDefinitionCount();
		// 根据documentReader读取BeanDefinitions; 后面会讲createReaderContext(resource)
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}
	// 通过反射实现,使用的Reader是可以进行自定义配置的
	protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
		return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
	}
	private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class;
进入DefaultBeanDefinitionDocumentReader.registerBeanDefinitions:
	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;
		// 获取Document的根节点
		Element root = doc.getDocumentElement();
		// 从根节点进行加载
		doRegisterBeanDefinitions(root);
	}

```java
	protected void doRegisterBeanDefinitions(Element root) {
		// bean定义解析委托给BeanDefinitionParserDelegate 
		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(getReaderContext(), root, parent);
		
		if (this.delegate.isDefaultNamespace(root)) {
			// 读取profile属性,根据profile进行bean的注册,不符合profile的bean就不进行注册
			String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
			if (StringUtils.hasText(profileSpec)) {
				String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
						profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
				if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
					return;
				}
			}
		}
		// 解析前
		preProcessXml(root);
		// 开始解析BeanDefinitions
		parseBeanDefinitions(root, this.delegate);
		// 解析后
		postProcessXml(root);
		this.delegate = parent;
	}
前面已经获取了Document、根据Profile选取要加载的Beans,并将解析的工作委托给DefaultBeanDefinitionDocumentReader,接下来看DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)对每个Element进行解析:
	/**
	 * Parse the elements at the root level in the document:
	 * "import", "alias", "bean".
	 * @param root the DOM root element of the document
	 */
	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		// 如果是默认的命名空间http://www.springframework.org/schema/beans
		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);
					}
				}
			}
		}
		// 否则根据自定义的XSD进行自定义节点的解析
		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);
		}
	}
前面我们水桶有了beanDefinitionMap,水也取到了parseBeanDefinitions,那后来水是如何放入水桶的呢?:

那就是在上面提到的processBeanDefinition方法了:

	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		// 解析BeanDefinition,并交给BeanDefinitionHolder 持有。
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			// 添加bean的其他属性,如scope,lazy-init等
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// 将bean注册进工厂 ,看下面
				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
	public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
			throws BeanDefinitionStoreException {

		// 获取beanName,通过注册器BeanDefinitionRegistry 将bean注入到工厂中。这个注册器是XmlBeanDefinitionReader提供的
		String beanName = definitionHolder.getBeanName();
		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
	    ......
	}

上面提到的注册器是XmlBeanDefinitionReader提供的,如果你还记得,一开始的XmlBeanFactory定义的就是这个XmlBeanDefinitionReader(this),并将DefaultListableBeanFactory实现的BeanDefinitionRegistry注入到XmlBeanDefinitionReader中。而在registerBeanDefinitions(Document doc, Resource resource)中,createReaderContext方法又将XmlBeanDefinitionReader传递下去,使解析的时候可以通过getReaderContext().getRegistry()获取到一开始在DefaultListableBeanFactory实现的BeanDefinitionRegistry。

而registerBeanDefinition又是DefaultListableBeanFactory实现的

	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		BeanDefinition oldBeanDefinition;
		synchronized (this.beanDefinitionMap) {
			oldBeanDefinition = this.beanDefinitionMap.get(beanName);
			if (oldBeanDefinition != null) {
				//......校验
			}
			else {
				this.beanDefinitionNames.add(beanName);
				this.frozenBeanDefinitionNames = null;
			}
			// 将beanDefinition加入到beanDefinitionMap中
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
	}
总结:

这是一个拿桶,取水,装水的过程。先看整体,再仔细看细节。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值