最近在看<spring源码深度解析>这本书,自己在GitHub上也下载了源码,DEBUG配合着看,做点笔记,加深下印象!巩固下知识.顺道给大伙分享下,有问题多多指教。一起进步哈。

版本:spring5.1.x

@Test
	public void testSimpleLoad(){
		//xmlBeanFactory 方式
		//整个xml的解析都是在这步完成的
		BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));
		//创建获取bean的过程
		MyTestBean bean = (MyTestBean) bf.getBean("myTestBean");
        Assert.notNull(bean,"Bean must be not null !");
	}

XmlBeanFactory这种获取bean的方式已经被废弃了,不推荐使用,但无所谓,主要目的是看他的bean的获取的整个流程。

BeanFactory bf = new XmlBeanFactory(new ClassPathResource(“beanFactoryTest.xml”));

时序图:

spring filter 源码_XML

测试代码很清晰,通过XmlBeanFactory()构造方法执行xml文件的读取,解析等操作,我们先看下XmlBeanFactory这类的UML图,关联确实有点复杂

spring filter 源码_spring filter 源码_02


再看下XmlBeanFactory这类的代码

@Deprecated
@SuppressWarnings({"serial", "all"})
public class XmlBeanFactory extends DefaultListableBeanFactory {

	private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);

	/**
	 * Create a new XmlBeanFactory with the given resource,
	 * which must be parsable using DOM.
	 * @param resource the XML resource to load bean definitions from
	 * @throws BeansException in case of loading or parsing errors
	 */
	public XmlBeanFactory(Resource resource) throws BeansException {
		this(resource, null);
	}

	/**
	 * Create a new XmlBeanFactory with the given input stream,
	 * which must be parsable using DOM.
	 * @param resource the XML resource to load bean definitions from
	 * @param parentBeanFactory parent bean factory
	 * @throws BeansException in case of loading or parsing errors
	 */
	public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
		super(parentBeanFactory);
		this.reader.loadBeanDefinitions(resource);
	}
}

这类很简单,通过XmlBeanDefinitionReader这类来解析xml文件,整个解析流程都是在 **this.reader.loadBeanDefinitions(resource)**这步完成的,其实spring框架的风格也是如此,方法很有层次的套着,这样整个代码看起来也比较清爽
看下super(parentBeanFactory) 这步最终的执行方法:

/**
	 * Create a new AbstractAutowireCapableBeanFactory.
	 */
	public AbstractAutowireCapableBeanFactory() {
		super();
		ignoreDependencyInterface(BeanNameAware.class);
		ignoreDependencyInterface(BeanFactoryAware.class);
		ignoreDependencyInterface(BeanClassLoaderAware.class);
	}

这个ignoreDependencyInterface()的作用是实例化一个bean A 时,如果他自动装配了属性B
该属性B实现了BeanNameAware,或者BeanFactoryAware ,或者BeanClassLoaderAware接口,那么
会调用过滤接口不会实例化,就是这作用,书上的原话是:

举例来说当A中有属性B,那么当Spring在获取A的Bean的时候如果其属性B还没有初始化,那么Spring会自动初始化B,这也是Spring中提供的一个重要特性,但是某些情况下B不会被初始化,其中的一种情况就是B实现了BeanNameAware接口。Spring中是这样介绍的:自动装配时忽略给定的依赖接口,典型应用是通过其他方式解析Application上下文注册依赖,类似于BeanFactory通过BeanFactoryAware进行注入或者ApplicationContext通过ApplicationContextAware进行注入

/**
	 * Load bean definitions from the specified XML file.
	 * @param resource the resource descriptor for the XML file
	 * @return the number of bean definitions found
	 * @throws BeanDefinitionStoreException in case of loading or parsing errors
	 */
	@Override
	public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
		return loadBeanDefinitions(new EncodedResource(resource));
	}

继续走下去,看下这个EncodedResource的构造方法

private EncodedResource(Resource resource, @Nullable String encoding, @Nullable Charset charset) {
		super();
		Assert.notNull(resource, "Resource must not be null");
		this.resource = resource;
		this.encoding = encoding;
		this.charset = charset;
	}

就是个编码属性的处理,继续,看下loadBeanDefinitions()方法

/**
	 * Load bean definitions from the specified XML file.
	 * @param encodedResource the resource descriptor for the XML file,
	 * allowing to specify an encoding to use for parsing the file
	 * @return the number of bean definitions found
	 * @throws BeanDefinitionStoreException in case of loading or parsing errors
	 */
	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的解析都是从这边开始处理的,里面嵌套着好几个方法

看下时序图

spring filter 源码_spring源码解析_03


这BeanFactory的实例创建大概就这个流程,具体的里面流程后面再更新。。。。