2、Bean的构建过程
2.1 创建bean
spring Ioc容器的实现,从根源上是beanfactory,但真正可以作为一个可以独立使用的ioc容器还是DefaultListableBeanFactory,因此可以这么说,DefaultListableBeanFactory 是整个spring ioc的始祖,研究透它的前生今世对我们理解spring ioc的概念有着重要的作用。
- bean类
package com.demo;
class User {
private UserDao userdao;
public void say() {
System.out.println("hello User.");
}
public UserDao getUserdao() {
return userdao;
}
public void setUserdao(UserDao userdao) {
this.userdao = userdao;
}
}
- 简单创建、存储、获取
package com.demo;
import org.junit.Test;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
public class BeanFactoryTest {
@Test
public void simpleBeanTest() {
DefaultListableBeanFactory fac = new DefaultListableBeanFactory();
// 创建bean
User user = fac.createBean(User.class);
// 注册bean
fac.registerSingleton("user", user);
// 获取bean
user = (User) fac.getBean("user");
// 测试一下
user.say();
}
}
- 存在依赖关系
有上面的User定义中可以看到,存在一个私有变量UserDao。
@Test
public void dependencyBeanTest() {
DefaultListableBeanFactory fac = new DefaultListableBeanFactory();
// 准备依赖的userdao
UserDao userdao = fac.createBean(UserDao.class);
fac.registerSingleton("userdao", userdao);
// 创建bean,并依赖注入UserDao对象。
User user = (User) fac.createBean(User.class, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, true);
// 注册bean
fac.registerSingleton("user", user);
// 获取bean
user = (User) fac.getBean("user");
// 测试一下
user.say();
}
2.2 bean的定义
BeanDefinition (Bean定义)
ioc 实现中 我们在xml 中描述的Bean信息最后 都将保存至BeanDefinition (定义)对象中,其中xml bean 与BeanDefinition 程一对一的关系。
由此可见,xml bean中设置的属性最后都会体现在BeanDefinition中。如:
**XML-bean ** | BeanDefinition |
---|---|
class | beanClassName |
scope | scope |
lazy-init | lazyInit |
constructor-arg | ConstructorArgument |
property | MutablePropertyValues |
factory-method | factoryMethodName |
destroy-method | AbstractBeanDefinition.destroyMethodName |
init-method | AbstractBeanDefinition.initMethodName |
autowire | AbstractBeanDefinition.autowireMode |
id | |
name |
- [ ] 演示查看 BeanDefinition 属性结构
spring.xml 文件中保存了我们对Bean的描述配置,BeanFactory 会读取这些配置然后生成对应的Bean。这是我们对ioc原理的一般理解。但在深入一些我们会有更多的问题?
- 配置信息最后是谁JAVA中哪个对象承载的?
- 这些承载对象是谁读取XML文件并装载的?
- 这些承载对象又是保存在哪里?
BeanDefinitionRegistry(Bean注册器)
在上表中我们并没有看到 xml bean 中的 id 和name属性没有体现在定义中,原因是ID 其作为当前Bean的存储key注册到了BeanDefinitionRegistry 注册器中。name 作为别名key 注册到了 AliasRegistry 注册中心。其最后都是指向其对应的BeanDefinition。
- [ ] 演示查看 BeanDefinitionRegistry属性结构
2.3 bean的加载
BeanDefinitionReader(Bean定义读取)
上图中可以看出Bean的定义是由BeanDefinitionReader 从xml 中读取配置并构建出 BeanDefinitionReader,然后在基于别名注册到BeanDefinitionRegister中。
- [ ] 查看BeanDefinitionReader结构
方法说明:
- **loadBeanDefinitions(Resource resource) **
- 基于资源装载Bean定义并注册至注册器
- int loadBeanDefinitions(String location)
- 基于资源路径装载Bean定义并注册至注册器
- BeanDefinitionRegistry getRegistry()
- 获取注册器
- ResourceLoader getResourceLoader()
- 获取资源装载器
- [ ] 基于示例演示BeanDefinitionReader装载过程
//创建一个简单注册器
BeanDefinitionRegistry register = new SimpleBeanDefinitionRegistry();
//创建bean定义读取器
BeanDefinitionReader reader = new XmlBeanDefinitionReader(register);
// 创建资源读取器
DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
// 获取资源
Resource xmlResource = resourceLoader.getResource("spring.xml");
// 装载Bean的定义
reader.loadBeanDefinitions(xmlResource);
// 打印构建的Bean 名称
System.out.println(Arrays.toString(register.getBeanDefinitionNames());
堆栈信息:
Beanfactory(bean 工厂)
有了Bean的定义就相当于有了产品的配方,接下来就是要把这个配方送到工厂进行生产了。在ioc当中Bean的构建是由BeanFactory 负责的。其结构如下:
方法说明:
- **getBean(String) **
- 基于ID或name 获取一个Bean
- **
T getBean(Class requiredType) ** - 基于Bean的类别获取一个Bean(如果出现多个该类的实例,将会报错。但可以指定 primary=“true” 调整优先级来解决该错误 )
- Object getBean(String name, Object... args)
- 基于名称获取一个Bean,并覆盖默认的构造参数
- boolean isTypeMatch(String name, Class<?> typeToMatch)
- 指定Bean与指定Class 是否匹配
以上方法中重点要关注getBean,当用户调用getBean的时候就会触发 Bean的创建动作,其是如何创建的呢?
堆栈信息:
#创建Bean堆栈
// 其反射实例化Bean
java.lang.reflect.Constructor.newInstance(Unknown Source:-1)
BeanUtils.instantiateClass()
//基于实例化策略 实例化Bean。也可以使用cglib的方式进行创建
SimpleInstantiationStrategy.instantiate()
AbstractAutowireCapableBeanFactory.instantiateBean()
// 执行Bean的实例化方法
AbstractAutowireCapableBeanFactory.createBeanInstance()
AbstractAutowireCapableBeanFactory.doCreateBean()
// 执行Bean的创建
AbstractAutowireCapableBeanFactory.createBean()
// 缓存中没有,调用指定Bean工厂创建Bean
AbstractBeanFactory$1.getObject()
// 从单例注册中心获取Bean缓存
DefaultSingletonBeanRegistry.getSingleton()
AbstractBeanFactory.doGetBean()
// 获取Bean
AbstractBeanFactory.getBean()
// 调用的客户类
com.spring.BeanFactoryExample.main()
Bean创建时序图:
从调用过程可以总结出以下几点:
- 调用BeanFactory.getBean() 会触发Bean的实例化。
- DefaultSingletonBeanRegistry 中缓存了单例Bean。
- Bean的创建与初始化是由AbstractAutowireCapableBeanFactory 完成的。
3、BeanFactory 与 ApplicationContext区别
BeanFactory 看下去可以去做IOC当中的大部分事情,为什么还要去定义一个ApplicationContext 呢?
ApplicationContext 结构图
从图中可以看到 ApplicationContext 它由BeanFactory接口派生而来,因而提供了BeanFactory所有的功能。除此之外context包还提供了以下的功能:
- MessageSource, 提供国际化的消息访问
- 资源访问,如URL和文件
- 事件传播,实现了ApplicationListener接口的bean
- 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层