Spring源码之IOC--第一章
2017-10-26 11:09
190 查看
对于IOC控制反转的核心流程涉及五个接口:
BeanFactory:它最大的作用是通过beanName或beanType来获得bean实例,她是所有IOC容器最根本的功能接口。
BeanDefinition:bean的定义接口。既然可以通过BeanFactory来获得bean实例,那么具体这个bean是什么样子的,是单例呢还是多例呢,是延迟加载呢还是立即加载呢,和其他的bean存在依赖关系吗?这个接口就是做这些定义的。
既然如此,那这些所谓的定义从哪来,那么就是我们的xml配置文件了(bean标签的内容)或者注解之类的,因此需要讲到资源来源Resource。
在这里有一个很重要的关键字lazy-init,可以指定bean的加载策略。(lazy-init在xml文件中)
Resource:
这就是我们所说的外部资源了。是对资源的抽象,每一个接口实现类都代表了一种资源类型,如ClasspathResource、URLResource,FileSystemResource等。每一个资源类型都封装了对某一种特定资源的访问策略。它是spring资源访问策略的一个基础实现,应用在很多场景。
BeanDefinitionReader
将外部资源(resource)转为一个bean数据结构(BeanDefinition),需要一个工具来解析,如果是xml,可以理解为对DOM解析。如XmlBeanDefinitionReader。
ApplicationContext:我们常说的容器,暂且不多介绍。
以上这些可以自己去翻源码看,这里就不贴出来了!!
针对以上的分析,我们可以自己写一个实现bean实例化的代码:
beans.xml:
1. <?xml version="1.0" encoding="UTF-8"?>
2. <beans xmlns="http://www.springframework.org/schema/beans"
3.
4000
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
5. <bean id="person" class="com.springframework.beans.test.Person"></bean>
6. </beans>
Person.java
1. public class Person {
2.
3. public void work(){
4. System.out.println("I am working");
5. }
6. }
TestDefaultListableBeanFactory.java :
1. package com.springframework.beans.test;
2.
3. import org.springframework.beans.factory.support.DefaultListableBeanFactory;
4. import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
5. import org.springframework.core.io.ClassPathResource;
6.
7.
8. public class TestDefaultListableBeanFactory {
9.
10. public static void main(String[] args) {
11. ClassPathResource classPathResource = new ClassPathResource("beans.xml");
12. DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
13. XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
14. xmlBeanDefinitionReader.loadBeanDefinitions(classPathResource);
15. System.out.println("numbers: " + defaultListableBeanFactory.getBeanDefinitionCount());
16. ((Person)defaultListableBeanFactory.getBean("person")).work();
17. }
18.}
以下是输出结果。
可以看到,结果与我们期望的是一样的,成功的解析了XML文件,并注册了一个bean定义,而且我们使用getBean方法也成功得到了Person的实例。
上述这段程序当中可以看出,bean工厂的初始化一共使用了四行程序。
第一行完成了我们的第一步,即资源定位,采用classpath定位,因为我的beans.xml文件是放在src下面的。
第二行创建了一个默认的bean工厂。
第三行创建了一个reader,从名字就不难看出,这个reader是用来读取XML文件的。这一步要多说一句,其中将我们创建的defaultListableBeanFactory作为参数传给了reader的构造函数,这里是为了第四步读取XML文件做准备。
第四行使用reader解析XML文件,并将读取的bean定义回调设置到defaultListableBeanFactory当中。其实回调这一步就相当于我们上述的注册这一步。
这个时候defaultListableBeanFactory已经被正确初始化了,我们已经可以使用它的一些方法了,比如上面所使用的获取bean个数,以及获得一个bean实例的方法。
但是我相信真正的开发当中,没有人会采用这样的方式去创造一个bean工厂,我们可以有更简单的方式。上面的四步,我们肯定希望一步就可以完成它。是的,这不是在做梦,就像下面这样。
1. package com.springframework.beans.test;
2.
3. import org.springframework.context.ApplicationContext;
4. import org.springframework.context.support.FileSystemXmlApplicationContext;
5.
6. public class TestApplicationContext {
7.
8. public static void main(String[] args) {
9. ApplicationContext applicationContext = new FileSystemXmlApplicationContext("classpath:beans.xml");
10. System.out.println("numbers: " + applicationContext.getBeanDefinitionCount());
11. ((Person)applicationContext.getBean("person")).work();
12. }
13. }
接下来就是见证奇迹的时刻了,输出结果如下图。
我们果然一步就完成了上面四步所做的事情。而且仔细看会发现日志信息当中,第二次采用FileSystemXmlApplicationContext时,日志信息多了许多,分别在上面的前面多了两行,后面多了两行,这说明别看我们是一步,但其实这里比上面做了更多的事情。这里利用到的是ApplicationContext,稍后分析。
BeanFactory:它最大的作用是通过beanName或beanType来获得bean实例,她是所有IOC容器最根本的功能接口。
BeanDefinition:bean的定义接口。既然可以通过BeanFactory来获得bean实例,那么具体这个bean是什么样子的,是单例呢还是多例呢,是延迟加载呢还是立即加载呢,和其他的bean存在依赖关系吗?这个接口就是做这些定义的。
既然如此,那这些所谓的定义从哪来,那么就是我们的xml配置文件了(bean标签的内容)或者注解之类的,因此需要讲到资源来源Resource。
在这里有一个很重要的关键字lazy-init,可以指定bean的加载策略。(lazy-init在xml文件中)
Resource:
这就是我们所说的外部资源了。是对资源的抽象,每一个接口实现类都代表了一种资源类型,如ClasspathResource、URLResource,FileSystemResource等。每一个资源类型都封装了对某一种特定资源的访问策略。它是spring资源访问策略的一个基础实现,应用在很多场景。
BeanDefinitionReader
将外部资源(resource)转为一个bean数据结构(BeanDefinition),需要一个工具来解析,如果是xml,可以理解为对DOM解析。如XmlBeanDefinitionReader。
ApplicationContext:我们常说的容器,暂且不多介绍。
以上这些可以自己去翻源码看,这里就不贴出来了!!
针对以上的分析,我们可以自己写一个实现bean实例化的代码:
beans.xml:
1. <?xml version="1.0" encoding="UTF-8"?>
2. <beans xmlns="http://www.springframework.org/schema/beans"
3.
4000
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
5. <bean id="person" class="com.springframework.beans.test.Person"></bean>
6. </beans>
Person.java
1. public class Person {
2.
3. public void work(){
4. System.out.println("I am working");
5. }
6. }
TestDefaultListableBeanFactory.java :
1. package com.springframework.beans.test;
2.
3. import org.springframework.beans.factory.support.DefaultListableBeanFactory;
4. import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
5. import org.springframework.core.io.ClassPathResource;
6.
7.
8. public class TestDefaultListableBeanFactory {
9.
10. public static void main(String[] args) {
11. ClassPathResource classPathResource = new ClassPathResource("beans.xml");
12. DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
13. XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
14. xmlBeanDefinitionReader.loadBeanDefinitions(classPathResource);
15. System.out.println("numbers: " + defaultListableBeanFactory.getBeanDefinitionCount());
16. ((Person)defaultListableBeanFactory.getBean("person")).work();
17. }
18.}
以下是输出结果。
可以看到,结果与我们期望的是一样的,成功的解析了XML文件,并注册了一个bean定义,而且我们使用getBean方法也成功得到了Person的实例。
上述这段程序当中可以看出,bean工厂的初始化一共使用了四行程序。
第一行完成了我们的第一步,即资源定位,采用classpath定位,因为我的beans.xml文件是放在src下面的。
第二行创建了一个默认的bean工厂。
第三行创建了一个reader,从名字就不难看出,这个reader是用来读取XML文件的。这一步要多说一句,其中将我们创建的defaultListableBeanFactory作为参数传给了reader的构造函数,这里是为了第四步读取XML文件做准备。
第四行使用reader解析XML文件,并将读取的bean定义回调设置到defaultListableBeanFactory当中。其实回调这一步就相当于我们上述的注册这一步。
这个时候defaultListableBeanFactory已经被正确初始化了,我们已经可以使用它的一些方法了,比如上面所使用的获取bean个数,以及获得一个bean实例的方法。
但是我相信真正的开发当中,没有人会采用这样的方式去创造一个bean工厂,我们可以有更简单的方式。上面的四步,我们肯定希望一步就可以完成它。是的,这不是在做梦,就像下面这样。
1. package com.springframework.beans.test;
2.
3. import org.springframework.context.ApplicationContext;
4. import org.springframework.context.support.FileSystemXmlApplicationContext;
5.
6. public class TestApplicationContext {
7.
8. public static void main(String[] args) {
9. ApplicationContext applicationContext = new FileSystemXmlApplicationContext("classpath:beans.xml");
10. System.out.println("numbers: " + applicationContext.getBeanDefinitionCount());
11. ((Person)applicationContext.getBean("person")).work();
12. }
13. }
接下来就是见证奇迹的时刻了,输出结果如下图。
我们果然一步就完成了上面四步所做的事情。而且仔细看会发现日志信息当中,第二次采用FileSystemXmlApplicationContext时,日志信息多了许多,分别在上面的前面多了两行,后面多了两行,这说明别看我们是一步,但其实这里比上面做了更多的事情。这里利用到的是ApplicationContext,稍后分析。
相关文章推荐
- Spring源码之IOC--第一章
- Spring源码解析之IoC容器主要接口设计
- spring源码:IOC(li)
- Spring源码(八)-Spring-IOC中的注解
- spring ioc 源码解析(二)
- springIOC源码解析(六)
- Spring源码解读-Spring IoC容器初始化之资源注册
- spring源码之IOC初始化
- Spring源码解析之二 ------ 自定义标签的解析和注册(IOC的第一步)
- Spring源码阅读(二)—IOC容器初始化
- (十)Spring事务处理 - IoC容器的事务处理源码分析
- Spring源码阅读之IoC容器初始化1 -- Resource定位
- spring IoC源码分析 (2)Resource定位
- Spring IOC/BeanFactory/ApplicationContext的工作流程/实现原理/初始化/依赖注入源码详解
- 对spring web启动时IOC源码研究
- Spring Ioc创建之BeanFactory创建源码分析
- 浅析Spring IoC源码(十一)Spring refresh()方法解析后记2
- 浅析Spring IoC源码(三)分析refresh()方法前的准备篇(一)
- Spring源码学习IOC(3):IoC容器载入Bean定义资源文件
- spring源码学习之路---IOC实现原理(三)