首先以一段简单的代码说明下BeanFactory的使用
public class SimpleBeanFactory {
public static void main(String[] args) {
Resource resource = new ClassPathResource("applicationContext.xml");
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(resource);
UserService1 userService1 = (UserService1) beanFactory.getBean("userService1");
userService1.hello();
}
}
Ioc容器的使用步骤
创建Ioc配置文件的抽象资源,这个抽象资源包含了BeanDefinition的定义信息。
创建一个BeanFactory,这里使用了DefaultListableBeanFactory。
创建一个载入BeanDefinition的读取器,这里使用XmlBeanDefinitionReader来载入XML文件形式的BeanDefinition,通过一个回调配置给BeanFactory。
从定义好的资源位置读入配置信息,具体的解析过程由XmlBeanDefinitionReader来完成。完成整个载入和注册Bean定义之后,需要的Ioc容器就建立起来了。这个时候我们就可以直接使用Ioc容器了。
loadBeanDefinitions加载BeanDefinition
- XmlBeanDefinitionReader.loadBeanDefinitions->doLoadBeanDefinitions
XmlBeanDefinitionReader.doLoadDocument ->DefaultDocumentLoader.loadDocument,使用sax解析xml文件
XmlBeanDefinitionReader.registerBeanDefinitions->DefaultBeanDefinitionDocumentReader.registerBeanDefinitions->doRegisterBeanDefinitions 把document解析成BeanDefinition.
- DefaultBeanDefinitionDocumentReader.parseBeanDefinitions, parseDefaultElement解析默认的节点,parseCustomElement 解析自定义元素节点 , 并调用BeanDefinitionReaderUtils.registerBeanDefinition把BeanDefinition注册到容器中。
- DefaultBeanDefinitionDocumentReader委托BeanDefinitionParserDelegate进行解析,parseBeanDefinitionElement解析并返回BeanDefinitionHolder对象。
- DefaultListableBeanFactory.registerBeanDefinition把生成的BeanDefinition对象注册到容器中。
可以看到,真正解析xml是在DefaultDocumentLoader中,组装BeanDefinition是在BeanDefinitionParserDelegate中,注册是在DefaultListableBeanFactory中。
对象的依赖注入
上边只完成了BeanDefinition的加载注册,而对象的初始化与注入则是在调用getBean时进行的。
- AbstractBeanFactory.getBean()方法,调用doGetBean.
- 如果是单例的,直接从缓存中取.
- 从父工厂中取实例
- 注册依赖关系,递归调用,首先初始化依赖的bean
- 对于单例的实例,getSingleton获取实例,第一次会调用createBean创建。
- 原型则直接调用createBean创建
- 使用getObjectForBeanInstance处理FactoryBean的返回。
AbstractAutowireCapableBeanFactory.createBean方法 。
调用resolveBeforeInstantiation对BeanPostProcessor进行回调
doCreateBean创建实例
createBeanInstance创建BeanWrapper,调autowireConstructor或instantiateBean。
当有复写父类的方法,会用cglib创建实例。
SimpleInstantiationStrategy.instantiate->CglibSubclassingInstantiationStrategy.instantiateWithMethodInjection实际调用cglib进行实例化对象。
AbstractAutowireCapableBeanFactory.populateBean装载依赖的属性
- 自动加载注解的属性
- 调用applyPropertyValues方法 对属性进行依赖注入
- 对于转换过的属性,直接调用 BeanWrapper.setPropertyValues设置属性
- 对于没有转换过的属性,调用BeanDefinitionValueResolver.resolveValueIfNecessary对属性进行转换。
以resolveReference为例,会调用依赖的beanFactory.getBean(refName)方法获取实例,这样形成递归调用,把所有依赖的对象都实例化出来。
ApplicationContext的设计
* 1.支持不同的信息源。扩展了MessageSource接口,这个接口为ApplicationContext提供了很多信息源的扩展功能,比如:国际化的实现为多语言版本的应用提供服务。
* 2.访问资源。这一特性主要体现在ResourcePatternResolver接口上,对Resource和ResourceLoader的支持,这样我们可以从不同地方得到Bean定义资源。
* 这种抽象使用户程序可以灵活地定义Bean定义信息,尤其是从不同的IO途径得到Bean定义信息。这在接口上看不出来,不过一般来说,具体ApplicationContext都是
* 继承了DefaultResourceLoader的子类。因为DefaultResourceLoader是AbstractApplicationContext的基类,关于Resource后面会有更详细的介绍。
* 3.支持应用事件。继承了接口ApplicationEventPublisher,为应用环境引入了事件机制,这些事件和Bean的生命周期的结合为Bean的管理提供了便利。
* 4.附件服务。EnvironmentCapable里的服务让基本的Ioc功能更加丰富。
* 5.ListableBeanFactory和HierarchicalBeanFactory是继承的主要容器。
以ClassPathXmlApplicationContext为例
1. 构造方法 调用setConfigLocations 方法设置配置文件配置。
2. refesh方法初始化窗口,这个是ApplicationContext的核心 。
3. AbstractApplicationContext.obtainFreshBeanFactory中调用refreshBeanFactory方法,在AbstractRefreshableApplicationContext中实现。
4. 创建一个BeanFactory,并调用loadBeanDefinitions装载BeanDefinition
5. reresh方法中,进行工厂的初始化,处理器,监听器的初始化。 生命周期方法的回调等操作。