【一步一步学习spring】【番外】IOC 设计原理与实现

2、Bean的构建过程

2.1 创建bean

spring Ioc容器的实现,从根源上是beanfactory,但真正可以作为一个可以独立使用的ioc容器还是DefaultListableBeanFactory,因此可以这么说,DefaultListableBeanFactory 是整个spring ioc的始祖,研究透它的前生今世对我们理解spring ioc的概念有着重要的作用。

img

  • 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

图片

spring.xml 文件中保存了我们对Bean的描述配置,BeanFactory 会读取这些配置然后生成对应的Bean。这是我们对ioc原理的一般理解。但在深入一些我们会有更多的问题?

  1. 配置信息最后是谁JAVA中哪个对象承载的?
  2. 这些承载对象是谁读取XML文件并装载的?
  3. 这些承载对象又是保存在哪里?

BeanDefinitionRegistry(Bean注册器)
在上表中我们并没有看到 xml bean 中的 id 和name属性没有体现在定义中,原因是ID 其作为当前Bean的存储key注册到了BeanDefinitionRegistry 注册器中。name 作为别名key 注册到了 AliasRegistry 注册中心。其最后都是指向其对应的BeanDefinition。

图片

2.3 bean的加载

BeanDefinitionReader(Bean定义读取)

图片

上图中可以看出Bean的定义是由BeanDefinitionReader 从xml 中读取配置并构建出 BeanDefinitionReader,然后在基于别名注册到BeanDefinitionRegister中。

图片
方法说明:

  • **loadBeanDefinitions(Resource resource) **
    • 基于资源装载Bean定义并注册至注册器
  • int loadBeanDefinitions(String location)
    • 基于资源路径装载Bean定义并注册至注册器
  • BeanDefinitionRegistry getRegistry()
    • 获取注册器
  • ResourceLoader getResourceLoader()
    • 获取资源装载器
//创建一个简单注册器
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创建时序图:
图片

从调用过程可以总结出以下几点:

  1. 调用BeanFactory.getBean() 会触发Bean的实例化。
  2. DefaultSingletonBeanRegistry 中缓存了单例Bean。
  3. Bean的创建与初始化是由AbstractAutowireCapableBeanFactory 完成的。

3、BeanFactory 与 ApplicationContext区别

BeanFactory 看下去可以去做IOC当中的大部分事情,为什么还要去定义一个ApplicationContext 呢?
ApplicationContext 结构图
图片

从图中可以看到 ApplicationContext 它由BeanFactory接口派生而来,因而提供了BeanFactory所有的功能。除此之外context包还提供了以下的功能:

  1. MessageSource, 提供国际化的消息访问
  2. 资源访问,如URL和文件
  3. 事件传播,实现了ApplicationListener接口的bean
  4. 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
posted @ 2018-09-03 14:54  麦兜爱学习  阅读(668)  评论(0编辑  收藏  举报