mini-spring 源码阅读(一) bean的创建过程

目录

 getBean

 createBean

doCreateBean

createBeanIstance 

getObjectForBeanInstance

applyPropertyValues

initializeBean

invokeInitMethods

getEarlyBeanReference


                                                                  图 一

 引用一张网图 这张图表示了spring bean 的 生命周期 后续会有出现

首先从一段简单的测试代码开始

这里使用了一个DefaultListableBeanFactory 工厂,先对工厂进行创建,然后创建PropertyValues 往里面存入PropertyValue(用于保存属性名和属性值)

然后再定义一个BeanDefinition(保存bean的信息,propertyValues , 类名)

最后调用工厂对象的registerBeanDefinition 对BeanDefinition进行注册

然后再从容器根据beanName 获取Bean,

由于这里是只分析bean的创建过程,所有就不分析registerBeanDefinition注册BeanDefinition的过程。

@Test
	public void testPopulateBeanWithPropertyValues() throws Exception {

		DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
		PropertyValues propertyValues = new PropertyValues();
		propertyValues.addPropertyValue(new PropertyValue("name", "derek"));
		propertyValues.addPropertyValue(new PropertyValue("age", 18));
		BeanDefinition beanDefinition = new BeanDefinition(Person.class, propertyValues);
		beanFactory.registerBeanDefinition("person", beanDefinition);

		Person person = (Person) beanFactory.getBean("person");
		Person person1 = (Person) beanFactory.getBean("person");
		System.out.println(person);
		assertThat(person.getName()).isEqualTo("derek");
		assertThat(person.getAge()).isEqualTo(18);
	}

我们一般是通过beanName来调用 getBean 去获取 bean

 getBean

1首先调用 getSingleton 会去容器尝试获取单例的 bean,判断获取的bean是否为空

2 如果从容器获取不到则调用 getBeanDefinition 获取BeanDefinition对象(这里的BeanDefinition是我们之前在测试代码里定义并往容器注册的那个)通过beanName 和beanDefinition 去调用 createBean 去创建 bean 返回后再调用 getObejctForBeanInstance

3 如果从容器获取到了 则之间调用   getObejctForBeanInstance

然后看一下 createBean 做了什么

 createBean

从这段简单的代码可以发现 createBean 并没有真正创建 bean 而是又交个了 doCreateBean完成,但是在此之前会调用  resolveBeforeInstantiation (去遍历后置处理器,判断处理器类型是否为 InstantiationAwareBeanPostProcessor ,如果是则调用 postProcessBeforeInstantiation 方法 代表 bean实例化前这一段生命周期

接着再追到 doCreateBean 里面

doCreateBean

 1 其实到了这里我们可以发现 bean 还是没有创建,而是把这个任务又交个 createBeanInstance 去完成 ,然后在创建好 bean 判断 bean 是否为单例

2 如果是则调用 addSingletonFactory (该方法就是把 bean 存入到三级缓存中,key : beanName 

value: ObjectFactory (ObjectFactory 是匿名实现类 ,实现了getObject 方法 ,该方法又调用 getEarlyBeanReference 去获取 bean) )

3 接着会调用  applyBeanPostProcessorsAfterInstantiation (该方法主要是遍历所有后置处理器 如果是  InstantiationAwareBeanPostProcessor 类型的就执行 postProcessAfterInstantiation 方法 代表 bean 实例化后的这一段生命周期 

4 调用 applyPropertyValues 对 bean 进行属性填充

5 调用  initializeBean 方法 (该方法主要)

          5.1判断 bean 是否实现了 BeanFactoryAware如果是则会回调对应的方法为bean 设置依赖 

          5.2 执行所有 BeanPostProcessor 的前置处理

          5.3 判断 bean 是否实现了 InitializingBean 如果是则 回调方法 afterPropertiesSet

               判断 bean 是否 配置了  initMethodName 如果配置了 则通过放射回调方法 initMethod 

          5.4  执行所有后置处理器的 后置处理 

6  对所有 实现了  DisposableBean 接口  或  BeanDefinition 配置 DestroyMethodName 的 bean 进行注册 

7 判断 bean 是否为单例,如果是则尝试获取代理对象,如果有则返回代理对象,没有则获取原始对象,但是不管有还是没有,最终都会都会将 bean 转移到 一级缓存,也就是 真正存储 单例 bean 的容器 

//真正创建bean的方法
	protected Object doCreateBean(String beanName, BeanDefinition beanDefinition) {
		Object bean;
		try {

			//生命周期一
			bean = createBeanInstance(beanDefinition);

			//为解决循环依赖问题,将实例化后的bean放进缓存中提前暴露
			if (beanDefinition.isSingleton()) {
				Object finalBean = bean;
				//添加到三级缓存容器,key为组件名,值为实现了ObjectFactory 的匿名类,实现了获取bean的方式,实际为从二级缓存获取
				addSingletonFactory(beanName, new ObjectFactory<Object>() {
					@Override
					public Object getObject() throws BeansException {
						//代理对象从这里返回
						return getEarlyBeanReference(beanName, beanDefinition, finalBean);
					}
				});
			}

			//实例化bean之后执行后置处理器的逻辑,判断是否有后置处理器执行过,有就返回false,没有就true
			boolean continueWithPropertyPopulation = applyBeanPostProcessorsAfterInstantiation(beanName, bean);
			if (!continueWithPropertyPopulation) {
				return bean;
			}
			//在设置bean属性之前,允许BeanPostProcessor修改属性值
			// applyBeanPostProcessorsBeforeApplyingPropertyValues
			// (beanName, bean, beanDefinition);
			//为bean填充属性
			//生命周期二
			applyPropertyValues(beanName, bean, beanDefinition);
			//执行bean的初始化方法和BeanPostProcessor的前置和后置处理方法
			bean = initializeBean(beanName, bean, beanDefinition);
		} catch (Exception e) {
			throw new BeansException("Instantiation of bean failed", e);
		}

		//注册有销毁方法的bean
		registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);

		Object exposedObject = bean;
		if (beanDefinition.isSingleton()) {
			//如果有代理对象,此处获取代理对象
			exposedObject = getSingleton(beanName);
			addSingleton(beanName, exposedObject);
		}
		return exposedObject;
	}

接着再去看 createBeanInstance 方法 

createBeanIstance 

虽然见名知义,但是该方法也并没有真正创建 bean , 而是通过getInstantiationStrategy().instantiate(beanDefinition) 去创建 (实际上获取了策略器,由策略器去真正的创建 bean )

我们看一下默认的策略器是如何创建对象的

轻轻爽爽,到这来我们可以知道, 真正创建bean 是由 InstantiationStrategy 去完成的,而默认的 InstantiationStrategySimpleInstantiationStrategy ,创建 bean 是通过反射创建 

这里就是 图一 的 bean 生命周期一 实例化 

如何我们也可以选择另外一中框架提供的策略器 CglibSubclassingInstantiationStrategy 该策略器主要是使用的 Cglib 来反射创建 bean

public class CglibSubclassingInstantiationStrategy implements InstantiationStrategy {

	/**
	 * 使用CGLIB动态生成子类
	 *
	 * @param beanDefinition
	 * @return
	 * @throws BeansException
	 */
	@Override
	public Object instantiate(BeanDefinition beanDefinition) throws BeansException {
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(beanDefinition.getBeanClass());
		enhancer.setCallback((MethodInterceptor) (obj, method, argsTemp, proxy) -> proxy.invokeSuper(obj,argsTemp));
		return enhancer.create();
	}
}

由此可知,创建 bean 会根据不同的策略器来使用不同的策略来创建 bean

接着再看看前面没有说的方法 

getObjectForBeanInstance

该方法在 getBean 里面调用

1 判断从容器里获取到的 bean 是否为 FactoryBean 如果且 FactoryBean 为单例则  从工厂缓存里尝试获取 bean 如果 获取不到再从 FactoryBean 里获取

2 如果不是单例,则直接从 FactoryBean 获取

applyPropertyValues

该方法主要功能时为 bean 进行属性填充

主要是获取 beandefinition 里的 PropertyValues 进行遍历,判断 bean 的依赖的属性是否为引用类型,如果是则调用 getBean 去获取依赖的对象进行注入,如果是常用数据类型则会先对类型进行装换再注入

注入也是使用到了工具类来完成

然后这里 就是 图一 的 bean 生命周期二 初始化

protected void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
		try {
			//从beanDefinition获取所有定义的propertyValue列表,然后遍历获取属性名和属性值,判断值的类型是否为
			//引用对象,是则先实例化依赖对象,调用getBean该方法就是我们在main里调用getBean获取组件的方法.
			for (PropertyValue propertyValue : beanDefinition.getPropertyValues().getPropertyValues()) {
				String name = propertyValue.getName();
				Object value = propertyValue.getValue();
				if (value instanceof BeanReference) {
					// beanA依赖beanB,先实例化beanB
					BeanReference beanReference = (BeanReference) value;
					value = getBean(beanReference.getBeanName());
				} else {
					//非引用类型 , 先获取值的类型,然后通过工具类获取bean对应属性名的类型
					//类型转换
					Class<?> sourceType = value.getClass();
					Class<?> targetType = (Class<?>) TypeUtil.getFieldType(bean.getClass(), name);
					//获取类型转换服务,如果不为空则判断原类型是否能转换为目标类型
					ConversionService conversionService = getConversionService();
					if (conversionService != null) {
						if (conversionService.canConvert(sourceType, targetType)) {
							//能则将值转为目标类型
							value = conversionService.convert(value, targetType);
						}
					}
				}

				//通过反射设置属性
				BeanUtil.setFieldValue(bean, name, value);
			}
		} catch (Exception ex) {
			throw new BeansException("Error setting property values for bean: " + beanName, ex);
		}
	}

initializeBean

该方法表示了图一 的 initialization 初始化 

 首先判断 bean 是否实现了 BeanFactoryAware如果是则会回调对应的方法为bean 设置依赖 

这也表示了图一的 sping bean 生命周期三 检查Aware接口并设置相关依赖

applyBeanPostProcessorsBeforeInitialization 调用后,里面表示了 spring bean 生命周期四 BeanPostProcesser的前置处理

等待 invokeInitMethods 执行完成后再调用 applyBeanPostProcessorsAfterInitialization

里面就是遍历所有的 beanPostProcesser 执行 后置处理

这表示了 spring bean生命周期 七

invokeInitMethods

该方法里包含了 spring bean生命周期的五 和 生命周期六 

首先判断 bean 是否实现了 InitializingBean ,如果实现了则回调 bean的  afterPropertiesSet 方法

这表示了 spring bean 生命周期五

然后判断用户是否配置了  InitMethod ,如果配置了也会回调 InitMethod 方法

这表示了 spring bean 生命周期六

	protected void invokeInitMethods(String beanName, Object bean, BeanDefinition beanDefinition) throws Throwable {
		//生命周期五
		if (bean instanceof InitializingBean) {
			((InitializingBean) bean).afterPropertiesSet();
		}
		String initMethodName = beanDefinition.getInitMethodName();
		//生命周期六
		if (StrUtil.isNotEmpty(initMethodName)) {
			Method initMethod = ClassUtil.getPublicMethod(beanDefinition.getBeanClass(), initMethodName);
			if (initMethod == null) {
				throw new BeansException("Could not find an init method named '" + initMethodName + "' on bean with name '" + beanName + "'");
			}
			initMethod.invoke(bean);
		}
	}

getEarlyBeanReference

该方法主要在匿名实现 ObjectFactory 类的 getObject里调用 

主要是遍历所有的  InstantiationAwareBeanPostProcessor 调用 getEarlyBeanReference 方法

protected Object getEarlyBeanReference(String beanName, BeanDefinition beanDefinition, Object bean) {
		Object exposedObject = bean;
		//获取bean前会变量bean的后置处理器,判断是否为后置处理器,是的话则调用
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				exposedObject = ((InstantiationAwareBeanPostProcessor) bp).getEarlyBeanReference(exposedObject, beanName);
				if (exposedObject == null) {
					return exposedObject;
				}
			}
		}

		return exposedObject;
	}

在进行追踪 InstantiationAwareBeanPostProcessor 的默认实现类

它的实现

其实就是在从三级容器获取 bean 时就把 bean 存入二级容器,然后调用 wrapIfNecessary 去返回 bean 

 对于后置处理的调用 则不分析了,因为都是一样的,一个循环遍历,然后判断是否要调用 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值