zoukankan      html  css  js  c++  java
  • Spring是怎么创建一个Bean的?

    1.前言

    大致分析了下Spring的getBean过程,但主要关注doCreateBean。

    2.整体流程

    调用链:preInstantiateSingletons->getBean->doGetBean->getSingleton-> singletonFactory.getObject()->createBean->doCreateBean

    图中,需要特别注意getBeancreateBeancreateBeanInstancepopulateBeaninitializeBean
    在这里插入图片描述

    3.preInstantiateSingletons 提前初始化非lazy的单实例

    SpringIOC源码学习总结可知,在Spring容器refresh的阶段会调用finishBeanFactoryInitialization->preInstantiateSingletons,然后提前实例化非lazy的单实例。

    3.1 getBean 得到/创建bean

    调用链:createBean->doGetBean->getSingleton
    在这里插入图片描述

    if (mbd.isSingleton()) {
    					sharedInstance = getSingleton(beanName, () -> {
    						try {
    						//doGetBean
    							return createBean(beanName, mbd, args);
    						}
    						catch (BeansException ex) {
    							destroySingleton(beanName);
    							throw ex;
    						}
    					});
    					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    				}
    

    3.2 getSingleton(String beanName, ObjectFactory<?> singletonFactory)获得单实例

    调用链:getSingleton->singletonFactory.getObject()->createBean

    在这里插入图片描述

    1. 先尝试中singletonObjects拿到Spring已经缓存的bean实例。
    2. 标记该bean【正创建中】
    3. 调用singletonFactory.getObject()->createBean创建bean。
    4. 添加到缓存。
    5. 去掉【正创建中】标记。
    6. 添加到缓存。

    getSingleton源码

    	synchronized (this.singletonObjects) {
    		Object singletonObject = this.singletonObjects.get(beanName);
    		if (singletonObject == null) {
    			//标记为该bean【正在创建】
    			beforeSingletonCreation(beanName);
    			...
    			//创建bean,重点关注
    			singletonObject = singletonFactory.getObject();
    			...
    			//添加到缓存
    			if (newSingleton) {
    				addSingleton(beanName, singletonObject);
    			}
    		}
    		return singletonObject;
    	}finally {
    		...
    		//去除 【正在创建】 的标记
    		afterSingletonCreation(beanName);
    	}
    

    3.2.1 createBean`创建bean

    调用链:createBean->doCreateBean

    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    		throws BeanCreationException {
    		...
    	RootBeanDefinition mbdToUse = mbd;
    	//从BeanDefinition中取出Class信息
    	Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    		//为bean设置<bean>标签中的<replaced-method>方法。实现方法重载
    		mbdToUse.prepareMethodOverrides();
    		...
    		//有机会创建代理对象,暂不理会这里
    		Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
    		...
    		//创建bean实例, 重点关注
    		Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    		...
    		return beanInstance;
    }
    

    3.3 getObjectForBeanInstance 处理FactoryBean

    在这里插入图片描述
    1.如果该bean是普通bean,则直接返回。如果该bean是FactoryBean,且getBean("&id")形式来获取,则返回该bean.
    2.否则是需要取FactoryBean#getObject对应的实例。因此调用该bean的getObject方法返回实例bean,并放入factoryBeanObjectCache缓存。

    关于FactoryBean可查看FactoryBean的作用

    4.doCreateBean(beanName, mbdToUse, args)

    终于到了今天的主角doCreateBean

    这里就不贴代码了, 太多了。需要看源码直接看AbstractAutowireCapableBeanFactory#doCreateBean 直接看下流程图:
    在这里插入图片描述

    流程:

    1. 创建实例:createBeanInstance(beanName, mbd, args)创建一个带有bean实例的BeanWrapper
    2. 收集注解:通过applyMergedBeanDefinitionPostProcessors调用BeanPostProcessor收集@Resource、@Autowired、@PreConstruct等注解。
    3. 提前暴露Bean:如果是需要提前暴露bean,则添加一个暴露没有注入属性的bean的方法到缓存addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));。此处是为了解决循环依赖,可查看:spring中怎么解决循环依赖
    4. 注入属性:populateBean除了处理标签中的property,还利用BeanPostProcessor去处理【2】中收集的@Resource、@Autowired等,完成依赖注入。—CommonAnnotationBeanPostProcessor以及AutowiredAnnotationBeanPostProcessor
    5. 初始化bean(完成注入后的操作):initializeBean,这里的钩子就比较多:
      a. invokeAwareMethods:响应BeanNameAware、BeanClassLoaderAware、BeanFactoryAware接口。
      b. applyBeanPostProcessorsBeforeInitialization:遍历BeanPostProcess调用BeanPostProcessor#postProcessBeforeInitialization
      c. invokeInitMethods:
      - InitializeBean.afterPropertiesSet:如果该bean有实现InitializeBean接口,则调用。
      - invokeCustomInitMethod(initMethod):如果有<bean>有配置init-method则调用。
      d. applyBeanPostProcessorsAfterInitialization:遍历BeanPostProcess调用BeanPostProcessor#postProcessAfterInitialization

    小结
    1.a为常用的Aware接口,b、d为常用的BeanPostProcessor接口,c为常用InitializingBean接口。
    2.重点类BeanpostProcessor:CommonAnnotationBeanPostProcessorAutowiredAnnotationBeanPostProcessor

    总结

    createBean 过程总之就是获得BeanDefinition的信息,通过反射创建实例,再注入依赖,然后initializeBean完成特殊处理,最后放入缓存中。 在整个过程中,留下了许多钩子,我们可以使用Aware接口,BeanPostProcessor去做特殊处理。

    最后再放一张详细的图:
    在这里插入图片描述

  • 相关阅读:
    克隆对象和对象的继承
    面向对象的目的和方式
    补充+复习
    正则的一些细节和拖拽时遇到的问题及解决方法
    js高级正则解析
    正则理解
    如何判断this指向?
    动画以及运动
    元素节点
    null和undefined的区别
  • 原文地址:https://www.cnblogs.com/thewindkee/p/12873100.html
Copyright © 2011-2022 走看看