低级容器BeanFactory
低级容器BeanFactory可以理解为就是个HashMap,Key是BeanName,Value是Bean实例,通常只提供注册(put),获取(get)这两个功能;是IOC容器的基础接口,所有的容器都是从它这里继承实现而来,BeanFactory作为SpringIOC容器,管理着Bean的生命周期,控制着Bean的依赖注入;
它实现的核心功能就是根据名称或类型来返回一个bean实例,一个工厂如果要具备这种功能它需要具备以下几个条件:
- 持有各种bean的定义,只有拿到了bean的定义信息,才能根据这些信息进行实例化;
- 持有各种bean之间的依赖关系,如果一个类中持有对另一个类的引用,那么在对该类进行实例化时,必须根据类之间的依赖关系对相关类也进行实例化,因此工厂必须获得类之间的依赖关系,否则无法正确实例化;
以上两种信息都依赖于我们的配置信息定义,比如xml配置文件,工厂需要一个工具来读取配置文件的信息,配置方式可以有:在XML中进行显式配置;在Java中进行显式配置;注解方式;
类的依赖关系通过注入方式实现:Spring提供了三种注入方式:构造方法注入;setter方法注入;注解方式注入;类的依赖关系及bean的属性定义保存在BeanDefinition(加载所有的Bean配置成BeanDefinition到容器中,如果Bean有依赖关系,则使用占位符暂时代替);
调用BeanFactory.getBean的时候,从BeanDefinition所属的Map里,拿出Class对象进行实例化,同时如果有依赖关系,将递归调用(原因:因为加载的顺序不同,很可能Bean_A依赖的Bean_B还没有加载好,也就无法从容器中获取)getBean方法(即如果碰到了属性是ref的(占位符),那么就从容器里获取这个Bean)——完成依赖注入;
高级容器ApplicationContext
比BeanFactory多了更多的功能,定义了一个refresh方法,用于刷新整个容器,即重新加载/刷新所有的bean;
- BeanFactory:能够管理和装配Bean;
- ResourcePatternResolver:能够加载资源文件;
//AnnotatinonConfigApplicationContext:从一个或多个基于Java的配置类中加载Spring应用上下文;
ApplicationContext context = new AnnotatinonConfigApplicationContext(com.cmos.DemoConfig.class);
//AnnotationConfigWebApplicationContext:从一个或多个基于Java的配置类中加载SpringWeb应用上下文。
ApplicationContext context = new ClassPathXmlApplicationContext("demo.xml");
//ClassPathXmlApplicationContext:从类路径下的一个或多个XML配置文件中加载上下文定义,把应用上下文的定义文件作为类资源
//FileSystemXmlApplicationContext:从文件系统下的一个或多个XML配置文件中加载上下文定义;
ApplicationContext context = new FileSystemXmlApplicationContext("c:/demo.xml");
XmlWebApplicationContext:从Web应用下的一个或多个XML配置文件中加载上下文定义;
- MessageResource:能够实现国际化等功能;
- ApplicationEventPublisher:能够注册监听器,实现监听机制;
refresh()方法里列出了IOC容器初始化的步骤,第一个方法是初始化准备,这里只是设置启动日期和活动标识以及执行属性源的初始化,走到抽象方法refreshBeanFactory(),IOC容器开始初始化,第一步先判断有没有现有的工厂,有的话就销毁掉,然后创建一个默认的工厂,也就是DefaultListableBeanFactory ,接下来两行代码是设置bean工厂的一些属性,注意看loadBeanDefinitions(beanFactory)这行,当创建了一个默认的bean工厂后,加载bean定义,首先定义了一个Reader,这个Reader就是用来读取xml配置文件,spring将资源返回的输入流包装以后传给了doLoadBeanDefinitions()方法,spring将包装的输入流解析成DOM文档,然后将DOM中包含的bean定义信息注册到IOC容器持有的Map<String,BeanDefinition>对象中,只要IOC容器持有了bean定义,就能正确的生产bean实例;
注:代码省略
Spring容器加载配置完整Bean
- ResourceLoader从存储介质中加载Spring配置信息,并使用Resource表示这个配置文件的资源;
- BeanDefinitionReader读取Resource所指向的配置文件资源,然后解析配置文件。配置文件中每一个<bean>解析成一个BeanDefinition对象,并保存到BeanDefinitionRegistry中;
- 容器扫描BeanDefinitionRegistry中的BeanDefinition,使用Java的反射机制自动识别出Bean工厂后处理后器(实现BeanFactoryPostProcessor接口)的Bean,然后调用这些Bean工厂后处理器对BeanDefinitionRegistry中的BeanDefinition进行加工处理,主要完成以下两项工作:
- 对使用到占位符的<bean>元素标签进行解析,得到最终的配置值,这意味对一些半成品式的BeanDefinition对象进行加工处理并得到成品的BeanDefinition对象;
- 对BeanDefinitionRegistry中的BeanDefinition进行扫描,通过Java反射机制找出所有属性编辑器的Bean(实现java.beans.PropertyEditor接口的Bean),并自动将它们注册到Spring容器的属性编辑器注册表中(PropertyEditorRegistry);
- Spring容器从BeanDefinitionRegistry中取出加工后的BeanDefinition,并调用InstantiationStrategy着手进行Bean实例化的工作;
- 在实例化Bean时,Spring容器使用BeanWrapper对Bean进行封装,BeanWrapper提供了很多以Java反射机制操作Bean的方法,它将结合该Bean的BeanDefinition以及容器中属性编辑器,完成Bean属性的设置工作;
- 利用容器中注册的Bean后处理器(实现BeanPostProcessor接口的Bean)对已经完成属性设置工作的Bean进行后续加工,直接装配出一个准备就绪的Bean;