Bean 实例化和获取

实例化Bean

Spring 实例化bean的时机有两个:

  1. IOC容器启动时候;
  2. 真正调用的时候;

如果bean声明为scope=singletonlazy-init=false,则容器启动时候就实例化该bean(Spring 默认就是此行为)。否则在调用时候再进行实例化。

IOC容器启动时实例化

回到AbstractApplicationContext.refresh(),包含了如下代码,即bean实例化的第一种情况,容器启动时,直接初始化Bean

1 // Instantiate all remaining (non-lazy-init) singletons. 2 finishBeanFactoryInitialization(beanFactory);

finishBeanFactoryInitialization()包含如下代码,初始化非延迟加载的单例Bean

1// Instantiate all remaining (non-lazy-init) singletons. 2 beanFactory.preInstantiateSingletons();

单例Bean的实际初始化:

1public void preInstantiateSingletons() throws BeansException { 2 for (String beanName : beanNames) { 3 RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); 4 if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { 5 getBean(beanName); 6 } 7}

通过beanName从上一个大的步骤生成的BeanDefinition集合中获取BeanDefinition。

通过BeanDefinition获取bean

1public Object getBean(String name) throws BeansException { 2 return doGetBean(name, null, null, false); 3}

doGetBean中处理的逻辑很多,为了减少干扰,下面只显示了创建bean的函数调用栈。

1protected <T> T doGetBean( 2 final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) 3 throws BeansException { 4 //创建bean 5 createBean(beanName, mbd, args); 6}

创建bean。

1protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException { 2 Object beanInstance = doCreateBean(beanName, mbdToUse, args); 3 return beanInstance; 4} 5protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) 6 throws BeanCreationException { 7 // 实例化bean 8 instanceWrapper = createBeanInstance(beanName, mbd, args); 9} 10protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) { 11 //实例化bean 12 return instantiateBean(beanName, mbd); 13} 14protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) { 15 //调用实例化策略进行实例化 16 beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, 17}

判断哪种动态代理方式实例化bean。

1public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) { 2 //使用JDK动态代理 3 if (bd.getMethodOverrides().isEmpty()) { 4 return BeanUtils.instantiateClass(constructorToUse); 5 } 6 else { 7 //使用CGLIB动态代理 8 return instantiateWithMethodInjection(bd, beanName, owner); 9 } 10}

不管哪种方式最终都是通过反射的形式完成了bean的实例化。

1public static <T> T instantiateClass(Constructor<T> ctor, Object... args) 2 ReflectionUtils.makeAccessible(ctor); 3 return ctor.newInstance(args); 4}

核心步骤:

  1. 容器启动时实例化,会遍历单例+非延时加载的所有BeanName列表;
  2. 通过BeanName获取对应的BeanDefinition;
  3. 使用BeanDefinition创建Bean的instanceWrapper,基于反射实现的(反射实现的动态代理,有JDK的动态代理或者CGILIB);

Bean实例化

继续回到doGetBean

1protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, 2 @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { 3 4 //获取beanName 5 final String beanName = transformedBeanName(name); 6 Object bean; 7 8 // 先检查该bean是否为单例且容器中是否已经存在例化的单例类. 9 Object sharedInstance = getSingleton(beanName); 10 //如果已存在该bean的单例类 11 if (sharedInstance != null && args == null) { 12 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); 13 } 14 15 else { 16 // 获取父BeanFactory 17 BeanFactory parentBeanFactory = getParentBeanFactory(); 18 //先判断该容器中是否注册了此bean,如果有则在该容器实例化bean,否则再到父容器实例化bean 19 if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { 20 // 如果父容器有该bean,则调用父beanFactory的方法获得该bean 21 return (T) parentBeanFactory.getBean(nameToLookup, args); 22 } 23 24 try { 25 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); 26 checkMergedBeanDefinition(mbd, beanName, args); 27 28 //如果该bean有依赖bean,先实递归例化依赖bean。 29 String[] dependsOn = mbd.getDependsOn(); 30 if (dependsOn != null) { 31 for (String dep : dependsOn) { 32 registerDependentBean(dep, beanName); 33 getBean(dep); 34 } 35 } 36 37 //如果scope为Singleton执行此逻辑 38 if (mbd.isSingleton()) { 39 sharedInstance = getSingleton(beanName, () -> { 40 try { 41 return createBean(beanName, mbd, args); 42 } 43 }); 44 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 45 } 46 // scope是prototype类型的 47 else if (mbd.isPrototype()) { 48 Object prototypeInstance = null; 49 try { 50 beforePrototypeCreation(beanName); 51 prototypeInstance = createBean(beanName, mbd, args); 52 } 53 finally { 54 afterPrototypeCreation(beanName); 55 } 56 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); 57 } 58 //如果scope为Request,Session,GolbalSession执行此逻辑 59 else { 60 String scopeName = mbd.getScope(); 61 final Scope scope = this.scopes.get(scopeName); 62 63 try { 64 Object scopedInstance = scope.get(beanName, () -> { 65 beforePrototypeCreation(beanName); 66 try { 67 return createBean(beanName, mbd, args); 68 } 69 finally { 70 afterPrototypeCreation(beanName); 71 } 72 }); 73 bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); 74 } 75 } 76 } 77 78 return (T) bean; 79 }

上面方法中首先调用getSingleton(beanName)方法来获取单例bean,如果获取到则直接返回该bean。方法调用栈如下:

1public Object getSingleton(String beanName) { 2 return getSingleton(beanName, true); 3} 4protected Object getSingleton(String beanName, boolean allowEarlyReference) { 5//从singletonObjects中获取bean。 6 Object singletonObject = this.singletonObjects.get(beanName); 7 return (singletonObject != NULL_OBJECT ? singletonObject : null); 8}

getSingleton方法先从singletonObjects属性中获取bean 对象,如果不为空则返回该对象,否则返回null。

singletonObjects保存的是什么?什么时候保存的呢?

回到doGetBean()函数继续分析。如果singletonObjects没有该bean的对象,进入到创建bean的逻辑。处理逻辑如下:

1//获取父beanFactory 2BeanFactory parentBeanFactory = getParentBeanFactory(); 3//如果该容器中没有注册该bean,且父容器不为空,则去父容器中获取bean后返回 4if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { 5 return parentBeanFactory.getBean(nameToLookup, requiredType); 6}

下面是判断容器中有没有注册bean的逻辑,此处beanDefinitionMap即为XMLBeanDefinitionReader处理xml配置后,注册BeanDefinition的位置。在注册bean的流程里已经说过所有的bean信息都会保存到该变量中。

1public boolean containsBeanDefinition(String beanName) { 2 Assert.notNull(beanName, "Bean name must not be null"); 3 return this.beanDefinitionMap.containsKey(beanName); 4}

如果该容器中已经注册过bean,继续往下走。

先获取该bean的依赖bean,如果存在子依赖bean,则先递归获取相应的依赖bean。

1String[] dependsOn = mbd.getDependsOn(); 2if (dependsOn != null) { 3 for (String dep : dependsOn) { 4 registerDependentBean(dep, beanName); 5 getBean(dep); 6 } 7}

依赖bean创建完成后,接下来就是创建自身bean实例了。

获取bean实例的处理逻辑有三种,即Singleton、Prototype、其它(request、session、global session),下面一一说明。

获取单例singleton实例

如果bean是单例模式,执行此逻辑。

1if (mbd.isSingleton()) { 2 sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() { 3 @Override 4 public Object getObject() throws BeansException { 5 //创建bean回调 6 return createBean(beanName, mbd, args); 7 }); 8 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 9}

获取单例bean,如果已经有该bean的对象直接返回。如果没有则创建单例bean对象,并添加到容器的singletonObjects Map中,以后直接从singletonObjects直接获取bean。

1public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { 2 synchronized (this.singletonObjects) { 3 Object singletonObject = this.singletonObjects.get(beanName); 4 //如果singletonObjects中没有该bean 5 if (singletonObject == null) { 6 //回调参数传进来的ObjectFactory的getObject方法,即调用createBean方法创建bean实例 7 singletonObject = singletonFactory.getObject(); 8 //置新创建单例bean标志位为true。 9 newSingleton = true; 10 if (newSingleton) { 11 //如果是新创建bean,注册新生成bean对象 12 addSingleton(beanName, singletonObject); 13 } 14 } 15 //返回获取的单例bean 16 return (singletonObject != NULL_OBJECT ? singletonObject : null); 17 } 18}

把新生成的单例bean加入到类型为MAP 的singletonObjects属性中,这也就是前面singletonObjects()方法中获取单例bean时从此Map中获取的原因。

1protected void addSingleton(String beanName, Object singletonObject) { 2 synchronized (this.singletonObjects) { 3 //把新生成bean对象加入到singletonObjects属性中。 4 this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT)); 5 6 this.registeredSingletons.add(beanName); 7 } 8}

获取Prototype实例

Prototype是每次获取该bean时候都新建一个bean,因此逻辑比较简单,直接创建一个bean后返回。

1else if (mbd.isPrototype()) { 2 Object prototypeInstance = null; 3 //创建bean 4 prototypeInstance = createBean(beanName, mbd, args); 5 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); 6}

获取request、session、global session的实例

1else { 2 //获取该bean的scope 3 String scopeName = mbd.getScope(); 4 //获取相应scope 5 final Scope scope = this.scopes.get(scopeName); 6 //获取相应scope的实例化对象 7 Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() { 8 @Override 9 public Object getObject() throws BeansException { 10 return createBean(beanName, mbd, args); 11 } 12 }); 13 bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); 14 }

从相应scope获取对象实例。每个scope均需要实现get(String name, ObjectFactory<?> objectFactory)方法来获取特定scope下面的Bean instance。

1public Object get(String name, ObjectFactory<?> objectFactory) { 2 RequestAttributes attributes = RequestContextHolder.currentRequestAttributes(); 3 //先从指定scope中获取bean实例,如果没有则新建,如果已经有直接返回 4 Object scopedObject = attributes.getAttribute(name, getScope()); 5 if (scopedObject == null) { 6 //回调函数调用createBean创建实例 7 scopedObject = objectFactory.getObject(); 8 //创建实例后保存到相应scope中 9 attributes.setAttribute(name, scopedObject, getScope()); 10 } 11 } 12 return scopedObject; 13}

判断scope,获取实例函数逻辑。从RequestAttributes中获取beanName属性的对象,如果获取成功则并表示对象存在,无需创建,否则需要createBean。

如果是RequestScope,那么从Requet中获取/设置;如果是global scope那么从Application中获取实例,如果是session scope 那么从session中获取/设置。

RequestAttributes中获取beanName属性的对象逻辑:

1public Object getAttribute(String name, int scope) { 2 //scope是request时 3 if (scope == SCOPE_REQUEST) { 4 //从request中获取实例 5 return this.request.getAttribute(name); 6 } 7 else { 8 PortletSession session = getSession(false); 9 if (session != null) { 10 //scope是globalSession时,从application中获取实例 11 if (scope == SCOPE_GLOBAL_SESSION) { 12 //从globalSession中获取实例 13 Object value = session.getAttribute(name, PortletSession.APPLICATION_SCOPE); 14 return value; 15 } 16 else { 17 //从session中获取实例 18 Object value = session.getAttribute(name); 19 return value; 20 } 21 } 22 return null; 23 } 24}

在相应scope中设置实例函数逻辑:

1public void setAttribute(String name, Object value, int scope) { 2 if (scope == SCOPE_REQUEST) { 3 this.request.setAttribute(name, value); 4 } 5 else { 6 PortletSession session = getSession(true); 7 if (scope == SCOPE_GLOBAL_SESSION) { 8 session.setAttribute(name, value, PortletSession.APPLICATION_SCOPE); 9 } 10 else { 11 session.setAttribute(name, value); 12 } 13 } 14}

怎么实现的依赖注入呢?

getBean() 方法获取各种scope类型的bean过程中,如果需要创建Bean,那么需要调用doCreateBean() 方法,该方法创建Bean分为2步:

  1. 通过BeanDefinition创建BeanWrapper包装实例,包装了bean实例(通过反射创建);

  2. 初始化bean,核心方法为populateBean(),设置bean的属性和完成依赖注入。

    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {

    1 // Instantiate the bean. 2 BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args); 3 final Object bean = instanceWrapper.getWrappedInstance(); 4 Class<?> beanType = instanceWrapper.getWrappedClass(); 5 6 // Initialize the bean instance. 7 Object exposedObject = bean; 8 //初始化bean 9 populateBean(beanName, mbd, instanceWrapper); 10 exposedObject = initializeBean(beanName, exposedObject, mbd); 11 12 // 注册bean的disposable方法。即bean的销毁方法 13 registerDisposableBeanIfNecessary(beanName, bean, mbd); 14 15 return exposedObject; 16}

populateBean中包括了如下的内容:

1 //属性依赖分析 2 PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null); 3 4 if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) { 5 MutablePropertyValues newPvs = new MutablePropertyValues(pvs); 6 // Add property values based on autowire by name if applicable. 7 if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) { 8 autowireByName(beanName, mbd, bw, newPvs); 9 } 10 // Add property values based on autowire by type if applicable. 11 if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) { 12 autowireByType(beanName, mbd, bw, newPvs); 13 } 14 pvs = newPvs; 15 } 16 17 18 //最后设置属性依赖 19 if (pvs != null) { 20 applyPropertyValues(beanName, mbd, bw, pvs); 21 }

从BeanDefinition 中获取属性配置,并切自动注入属性,自动注入的方法有autowireByNameautowireByType

autowireByName的实现如下:

1protected void autowireByName( 2 String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) { 3 4 String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw); 5 for (String propertyName : propertyNames) { 6 if (containsBean(propertyName)) { 7 Object bean = getBean(propertyName); 8 pvs.add(propertyName, bean); 9 registerDependentBean(propertyName, beanName); 10 } 11 } 12 } 13 }

通过beanName获取依赖的Bean列表。

然后继续运行populateBean,

总结

在doCreateBean时,调用populateBean方法,解析Bean的依赖Beans,并通过applyPropertyValues注入。

怎么解决循环依赖的?

spring bean初始化的核心过程:

  1. createBeanInstance:实例化bean
  2. populateBean:设置bean的属性
  3. initializeBean:调用bean的init方法

那么可能发生循环依赖的阶段在createBeanInstance,构造注入的时候和populateBean设值注入的时候,那么要解决循环引用也应该从初始化过程着手。

对于单例来说,在Spring容器整个生命周期内,有且只有一个对象,所以很容易想到这个对象应该存在Cache中,Spring为了解决单例的循环依赖问题,使用了三级缓存

1** Cache of singleton objects: bean name --> bean instance */ 2private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256); 3 4/** Cache of singleton factories: bean name --> ObjectFactory */ 5private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16); 6 7/** Cache of early singleton objects: bean name --> bean instance */ 8private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

三级缓存分别对应:

  • singletonObjects:单例对象的cache
  • earlySingletonObjects提前暴光的单例对象的Cache
  • singletonFactories : 单例对象工厂的cache

我们在创建bean的时候,首先想到的是从cache中获取这个单例的bean,这个缓存就是singletonObjects。从缓存singletonObjects中获取Bean的主要方法就就是:

1 protected Object getSingleton(String beanName, boolean allowEarlyReference) { 2 //从一级缓存singletonObjects中获取Bean 3 Object singletonObject = this.singletonObjects.get(beanName); 4 5 // 未从缓存中获取到Bean,切当前对象正在创建切 6 if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { 7 synchronized (this.singletonObjects) { 8 //从提前曝光的缓存中获取Bean 9 singletonObject = this.earlySingletonObjects.get(beanName); 10 if (singletonObject == null && allowEarlyReference) { 11 //使用单里对象的工厂方法创建单例提前曝光对象 12 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); 13 if (singletonFactory != null) { 14 singletonObject = singletonFactory.getObject(); 15 this.earlySingletonObjects.put(beanName, singletonObject); 16 this.singletonFactories.remove(beanName); 17 } 18 } 19 } 20 } 21 return singletonObject; 22 }

上面的代码需要解释两个参数:

  • isSingletonCurrentlyInCreation():判断当前单例bean是否正在创建中,也就是没有初始化完成(比如A的构造器依赖了B对象所以得先去创建B对象, 或则在A的populateBean过程中依赖了B对象,得先去创建B对象,这时的A就是处于创建中的状态。)
  • allowEarlyReference: 是否允许从singletonFactories中通过getObject拿到对象

分析getSingleton()的整个过程:

  1. Spring首先从一级缓存singletonObjects中获取;

  2. 如果获取不到,并且对象正在创建中,就再从二级缓存earlySingletonObjects中获取;

  3. 如果还是获取不到且允许singletonFactories通过getObject()获取,就从三级缓存singletonFactory.getObject()(三级缓存)获取,如果获取到了则:

    this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName);

从singletonFactories中移除,并放入earlySingletonObjects中。其实也就是从三级缓存移动到了二级缓存

从上面三级缓存的分析,我们可以知道,Spring解决循环依赖的诀窍就在于singletonFactories这个三级cache。这个cache的类型是ObjectFactory,定义如下:

1public interface ObjectFactory<T> { 2 T getObject() throws BeansException; 3}

singletonFactories缓存的添加发生在addSingletonFactory()addSingletonFactory()发生在createBeanInstance之后,populateBean之前:

1protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { 2 Assert.notNull(singletonFactory, "Singleton factory must not be null"); 3 synchronized (this.singletonObjects) { 4 if (!this.singletonObjects.containsKey(beanName)) { 5 this.singletonFactories.put(beanName, singletonFactory); 6 this.earlySingletonObjects.remove(beanName); 7 this.registeredSingletons.add(beanName); 8 } 9 } 10}

这里就是解决循环依赖的关键,这段代码发生在createBeanInstance之后,也就是说单例对象此时已经被创建出来(调用了构造器)。这个对象已经被生产出来了,虽然还不完美(还没有进行初始化的第二步和第三步),但是已经能被人认出来了(根据对象引用能定位到堆中的对象),所以Spring此时将这个对象提前曝光出来让大家使用。

这样做有什么好处呢?让我们来分析一下, 由于循环依赖导致问题:A的某个field或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象

  1. A首先完成了初始化的第一步,并且将自己提前曝光到singletonFactories中;
  2. 此时进行初始化的第二步,发现自己依赖对象B,此时就尝试去get(B),发现B还没有被create,所以走create流程,B在初始化第一步的时候发现自己依赖了对象A,于是尝试get(A),
  3. get(A)尝试一级缓存singletonObjects(肯定没有,因为A还没初始化完全),尝试二级缓存earlySingletonObjects(也没有),尝试三级缓存singletonFactories,由于A通过ObjectFactory将自己提前曝光了;
  4. 所以B能够通过ObjectFactory.getObject拿到A对象(虽然A还没有初始化完全,但是总比没有好呀);
  5. B拿到A对象后顺利完成了初始化阶段1、2、3,完全初始化之后将自己放入到一级缓存singletonObjects中。
  6. 此时返回A中,A此时能拿到B的对象顺利完成自己的初始化阶段2、3,最终A也完成了初始化,进去了一级缓存singletonObjects中,而且更加幸运的是,由于B拿到了A的对象引用,所以B现在hold住的A对象完成了初始化。

知道了这个原理时候,肯定就知道为啥Spring不能解决A的构造方法中依赖了B的实例对象,同时B的构造方法中依赖了A的实例对象这类问题了!因为加入singletonFactories三级缓存的前提是执行了构造器,所以构造器的循环依赖没法解决

--Posted from Rpc

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )

Spring中管理Bean依赖注入之后和Bean销毁之前的行为

    对于Singleton作用域的Bean,Spring容器将会跟踪它们的生命周期,容器知道何时实例化结束、何时销毁。Spring可以管理Bean在实例化结束之后和Bean销毁之前的行为。Bean依赖关系注入之后的行为:    Spring提供了两种方式在Bean全部属性设置成功后执行特定的行为:在Spring配置文件

Spring Bean注册解析(一)

       Spring是通过IoC容器对Bean进行管理的,而Bean的初始化主要分为两个过程:Bean的注册和Bean实例化。Bean的注册主要是指Spring通过读取配置文件获取各个bean的声明信息,并且对这些信息进行注册的过程。Bean的实例化则指的是Spring通过Bean的注册信息对各个Bean进行实例化的过程。本文主要讲解Spring是如何