@@ -107,7 +107,7 @@ XML配置文件的读取是Spring中重要的功能,因为Spring的大部分
107107通过实现接口BeanDefinitionDocumentReader的DefaultBeanDefinitionDocumentReader类对Document进行解析,并使用BeanDefinitionParserDelegate对Element进行解析。
108108
109109## 容器的基础XmlBeanFactory
110- ``` java
110+ ```
111111BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));
112112```
113113时序图从BeanFactoryTest测试类开始,通过时序图我们可以一目了然地看到整个逻辑处理顺序。在测试的BeanFactoryTest中首先调用ClassPathResource的构造函数来构造Resource资源文件的实例对象,这样后续的资源处理就可以用Resource提供的各种服务来操作了,当我们有了Resource后就可以进行XmlBeanFactory的初始化了。那么Resource资源是如何封装的呢?
@@ -140,7 +140,7 @@ Resource接口抽象了所有Spring内部使用到的底层资源:File、URL
140140对不同来源的资源文件都有相应的Resource实现:文件(FileSystemResource)、Classpath资源(ClassPathResource)、URL资源(UrlResource)、InputStream资源(InputStreamResource)、Byte数组(ByteArrayResource)等。
141141
142142在日常的开发工作中,资源文件的加载也是经常用到的,可以直接使用Spring提供的类,比如在希望加载文件时可以使用以下代码:
143- ``` java
143+ ```
144144Resource resource=new ClassPathResource("beanFactoryTest.xml");
145145InputStream inputStream=resource.getInputStream();
146146```
@@ -149,15 +149,15 @@ InputStream inputStream=resource.getInputStream();
149149有了Resource接口便可以对所有资源文件进行统一处理。至于实现,其实是非常简单的,以getInputStream为例,ClassPathResource中的实现方式便是通过class或者classLoader提供的底层方法进行调用,而对于FileSystemResource的实现其实更简单,直接使用FileInputStream对文件进行实例化。
150150
151151ClassPathResource.java
152- ``` java
152+ ```
153153if (this.clazz != null) {
154154 is = this.clazz.getResourceAsStream(this.path);
155155 }else {
156156 is = this.classLoader.getResourceAsStream(this.path);
157157 }
158158```
159159FileSystemResource.java
160- ``` java
160+ ```
161161public InputStream getInputStream() throws IOException {
162162 return new FileInputStream(this.file);
163163 }
@@ -166,14 +166,14 @@ public InputStream getInputStream() throws IOException {
166166
167167了解了Spring中将配置文件封装为Resource类型的实例方法后,我们就可以继续探寻XmlBeanFactory的初始化过程了,XmlBeanFactory的初始化有若干办法,Spring中提供了很多的构造函数,在这里分析的是使用Resource实例作为构造函数参数的办法,代码如下:
168168XmlBeanFactory.java
169- ``` java
169+ ```
170170public XmlBeanFactory(Resource resource) throws BeansException {
171171 //调用XmlBeanFactory(Resource,BeanFactory)构造方法
172172 this(resource, null);
173173}
174174```
175175构造函数内部再次调用内部构造函数:
176- ``` java
176+ ```
177177//parentBeanFactory为父类BeanFactory用于factory合并,可以为空
178178public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws
179179BeansException {
@@ -182,7 +182,7 @@ BeansException {
182182}
183183```
184184上面函数中的代码this.reader.loadBeanDefinitions(resource) 才是资源加载的真正实现,也是我们分析的重点之一。我们可以看到时序图中提到的XmlBeanDefinitionReader加载数据就是在这里完成的,但是在XmlBeanDefinitionReader加载数据前还有一个调用父类构造函数初始化的过程:super(parentBeanFactory),跟踪代码到父类AbstractAutowireCapableBeanFactory的构造函数中:
185- ``` java
185+ ```
186186public AbstractAutowireCapableBeanFactory() {
187187 super();
188188 ignoreDependencyInterface(BeanNameAware.class);
@@ -253,7 +253,14 @@ public void refresh() throws BeansException, IllegalStateException {
253253 }
254254```
255255
256+ ## Bean创建
257+ 个人认为在 Spring 中Bean的 创建时可以分为两个阶段:
258+
259+ Bean对应的BeanDefinition 的创建。BeanDefinition 创建是在 ConfigurationClassPostProcessor 中完成
260+
261+ Bean 实例的创建。Bean实例的创建是在 AbstractApplicationContext#finishBeanFactoryInitialization 中完成
256262
263+ 之所以需要创建BeanDefinition 是因为在 Spring容器中,Bean的创建并非仅仅通过反射创建就结束了,在创建过程中,需要考虑到Bean针对Spring容器中的一些属性,所以BeanDefinition 中不仅仅包含了 Bean Class 文件信息,还包含了 当前Bean在Spring容器中的一些属性,比如在容器中的作用域、是否懒加载、别名等信息。当Bean 进行实例化创建时需要依赖于对应的BeanDefinition 提供对应的信息。
257264
258265
259266
0 commit comments