SpringloC容器的依赖注入源码解析(2)—— doGetBean之从缓存获取Bean

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 直接打开AbstractBeanFactory的doGetBean方法:

文章目录


79.png


直接打开AbstractBeanFactory的doGetBean方法:


protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
      @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
   // 先将方法传入的name转换成容器真实的beanName
   // 之前可以通过三种形式获取beanName
   // 一个是原始的beanName,一个是加了&的,一个是别名
   final String beanName = transformedBeanName(name);
   Object bean;
   // Eagerly check singleton cache for manually registered singletons.
   Object sharedInstance = getSingleton(beanName);
   // 加果先前已经创建过单例Bean的实例,并且调用的getBean方法传入的参数为空,则执行理面的逻辑
   // args之所以要求为空是因为如果有args,则需要做进一步赋值,因此无法直接返回
   if (sharedInstance != null && args == null) {
      if (logger.isTraceEnabled()) {
         // 如果Bean还在创建中,则说明是循环引用
         if (isSingletonCurrentlyInCreation(beanName)) {
            logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                  "' that is not fully initialized yet - a consequence of a circular reference");
         }
         else {
            logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
         }
      }
      // 如果是普通bean,直接返回,如果是FactoryBean,则返回他的getObject
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }
   else {
      // Fail if we're already creating this bean instance:
      // We're assumably within a circular reference.
      if (isPrototypeCurrentlyInCreation(beanName)) {
         throw new BeanCurrentlyInCreationException(beanName);
      }
      // Check if bean definition exists in this factory.
      BeanFactory parentBeanFactory = getParentBeanFactory();
      if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
         // Not found -> check parent.
         String nameToLookup = originalBeanName(name);
         if (parentBeanFactory instanceof AbstractBeanFactory) {
            return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                  nameToLookup, requiredType, args, typeCheckOnly);
         }
         else if (args != null) {
            // Delegation to parent with explicit args.
            return (T) parentBeanFactory.getBean(nameToLookup, args);
         }
         else if (requiredType != null) {
            // No args -> delegate to standard getBean method.
            return parentBeanFactory.getBean(nameToLookup, requiredType);
         }
         else {
            return (T) parentBeanFactory.getBean(nameToLookup);
         }
      }
      if (!typeCheckOnly) {
         markBeanAsCreated(beanName);
      }
      try {
         final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
         checkMergedBeanDefinition(mbd, beanName, args);
         // Guarantee initialization of beans that the current bean depends on.
         String[] dependsOn = mbd.getDependsOn();
         if (dependsOn != null) {
            for (String dep : dependsOn) {
               if (isDependent(beanName, dep)) {
                  throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
               }
               registerDependentBean(dep, beanName);
               try {
                  getBean(dep);
               }
               catch (NoSuchBeanDefinitionException ex) {
                  throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
               }
            }
         }
         // Create bean instance.
         // 如果BeanDefinition为单例
         if (mbd.isSingleton()) {
            // 这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
            sharedInstance = getSingleton(beanName, () -> {
               try {
                  return createBean(beanName, mbd, args);
               }
               catch (BeansException ex) {
                  // Explicitly remove instance from singleton cache: It might have been put there
                  // eagerly by the creation process, to allow for circular reference resolution.
                  // Also remove any beans that received a temporary reference to the bean.
                  destroySingleton(beanName);
                  throw ex;
               }
            });
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
         }
         else if (mbd.isPrototype()) {
            // It's a prototype -> create a new instance.
            Object prototypeInstance = null;
            try {
               beforePrototypeCreation(beanName);
               prototypeInstance = createBean(beanName, mbd, args);
            }
            finally {
               afterPrototypeCreation(beanName);
            }
            bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
         }
         else {
            String scopeName = mbd.getScope();
            final Scope scope = this.scopes.get(scopeName);
            if (scope == null) {
               throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
            }
            try {
               Object scopedInstance = scope.get(beanName, () -> {
                  beforePrototypeCreation(beanName);
                  try {
                     return createBean(beanName, mbd, args);
                  }
                  finally {
                     afterPrototypeCreation(beanName);
                  }
               });
               bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
            }
            catch (IllegalStateException ex) {
               throw new BeanCreationException(beanName,
                     "Scope '" + scopeName + "' is not active for the current thread; consider " +
                     "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                     ex);
            }
         }
      }
      catch (BeansException ex) {
         cleanupAfterBeanCreationFailure(beanName);
         throw ex;
      }
   }
   // Check if required type matches the type of the actual bean instance.
   if (requiredType != null && !requiredType.isInstance(bean)) {
      try {
         T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
         if (convertedBean == null) {
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
         }
         return convertedBean;
      }
      catch (TypeMismatchException ex) {
         if (logger.isTraceEnabled()) {
            logger.trace("Failed to convert bean '" + name + "' to required type '" +
                  ClassUtils.getQualifiedName(requiredType) + "'", ex);
         }
         throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
      }
   }
   return (T) bean;
}

第一行先将方法传入的name转换成容器真实的beanName,回顾之前,可以通过三种形式获取beanName,一个是原始的beanName,一个是加了&的,一个是别名


final String beanName = transformedBeanName(name);
Object bean;


进入到transformedBeanName方法里面


protected String transformedBeanName(String name) {
   return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
public static String transformedBeanName(String name) {
   Assert.notNull(name, "'name' must not be null");
   if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
      return name;
   }
   return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
      do {
         beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
      }
      while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
      return beanName;
   });
}

先看看是否是以&前缀开始的,不是的话直接返回name,是的话将&全部去掉。


再进入到canonicalName方法里:


public String canonicalName(String name) {
   String canonicalName = name;
   // Handle aliasing...
   String resolvedName;
   do {
       // 根据别名获取真正的beanName,传入beanName就啥都获取不到
      resolvedName = this.aliasMap.get(canonicalName);
      if (resolvedName != null) {
         canonicalName = resolvedName;
      }
   }
   while (resolvedName != null);
   return canonicalName;
}


如果能在map里找到真名,则证明传入的是别名,为了防止是别名的别名,这里有一个递归操作直到找不到,此时为真名


回到doGetBean,获取到beanName之后就尝试去缓存获得Bean实例


Object sharedInstance = getSingleton(beanName);

进入方法里


public Object getSingleton(String beanName) {
   return getSingleton(beanName, true);
}


第二个参数控制是否允许非延迟加载,true表示允许立即加载

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   // 尝试从一级缓存里面获取完备的Bean
   Object singletonObject = this.singletonObjects.get(beanName);
   // 如果完备的单例还没有创建出来,创建中的Bean的名字会被保存在singletonsCurrentlyInCreation中
   // 因此看看是否正在创建
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      // 尝试给一级缓存对象加锁,因为接下来就要对缓存对象操作了
      synchronized (this.singletonObjects) {
          // 尝试从二级缓存earlySingletonObjects这个存储还没进行属性添加操作的Bean实例缓存中获取
         singletonObject = this.earlySingletonObjects.get(beanName);
         // 如果还没有获取到并且第二个参数为true,为true则表示bean允许被循环引用
         if (singletonObject == null && allowEarlyReference) {
            // 从三级缓存singletonFactories这个ObjectFactory实例的缓存里尝试获取创建此Bean的单例工厂实例  
            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
            // 如果获取到工厂实例
            if (singletonFactory != null) {
               // 调用单例工厂的getObject方法返回对象实例 
               singletonObject = singletonFactory.getObject();
               // 将实例放入二级缓存里
               this.earlySingletonObjects.put(beanName, singletonObject);
               // 从三级缓存里移除
               this.singletonFactories.remove(beanName);
            }
         }
      }
   }
   return singletonObject;
}


该方法在DefaultSingletonBeanRegistry类里,负责对容器创建出来的单例进行注册,从一个map (singletonObjects)中尝试获取key为beanName的单例实例,其中singletonObjects就是一级缓存。


if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) 

保证从一级缓存里没有获取到相关实例,并且该实例一定是当前正在创建的实例

public boolean isSingletonCurrentlyInCreation(String beanName) {
   return this.singletonsCurrentlyInCreation.contains(beanName);
}


isSingletonCurrentlyInCreation方法会去查询一个set,看看正在创建的单例bean名单里是否有beanName,如果此时bean是单例的且正在创建,则会给一级缓存加一个同步锁,之后再操作另外两层缓存。


为了提高性能,二级缓存earlySingletonObjects和三级缓存singletonFactories都是HashMap,因为前面已经对一级缓存加了锁,所以是安全的。


首先尝试从二级缓存里获取Bean实例


singletonObject = this.earlySingletonObjects.get(beanName);


二级缓存里存的是还没有实例化的Bean(没执行populate)


之后又可能从三级缓存singletonFactories里尝试获取,这里存储的是Bean对应的ObjectFactory实例(工厂),后续可以通过getObject()来创建Bean的实例,由于Bean实例的属性可能还没有注入,所以先将其放入二级缓存里,然后从三级缓存里清除(保证三级缓存里只有一级保存Bean实例,避免重复创建Bean实例打破单例),之所以没有注入的Bean也要返回的原因是为了打破循环依赖问题。


回到doGetBean,


80.png


如果先前已经创建过单例Bean的实例,并且调用的getBean方法传入的参数为空,则执行理面的逻辑,args之所以要求为空是因为,如果有args,则需要做进一步赋值,因此无法直接返回。


无论是否有循环引用,最终都是要调用getObjectForBeanInstance返回Bean实例,但由于我们可能获取到的是工厂而非实例,所以还可能要多一步由工厂创建bean实例的步骤。


protected Object getObjectForBeanInstance(
      Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
   // Don't let calling code try to dereference the factory if the bean isn't a factory.
   if (BeanFactoryUtils.isFactoryDereference(name)) {
      if (beanInstance instanceof NullBean) {
         return beanInstance;
      }
      // 如果name是以&开头的但是不是FactoryBean,则直接抛出异常
      if (!(beanInstance instanceof FactoryBean)) {
         throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
      }
      if (mbd != null) {
         mbd.isFactoryBean = true;
      }
      return beanInstance;
   }
   // Now we have the bean instance, which may be a normal bean or a FactoryBean.
   // If it's a FactoryBean, we use it to create a bean instance, unless the
   // caller actually wants a reference to the factory.
   // 如果是一个普通的Bean,则直接返回
   if (!(beanInstance instanceof FactoryBean)) {
      return beanInstance;
   }
   // FactoryBean创建出bean实例返回
   Object object = null;
   if (mbd != null) {
      mbd.isFactoryBean = true;
   }
   else {
      // 单例模式下,FactoryBean仅会创建一个Bean实例
      // 因此需要优先从缓存获取,这里的缓存不是前面的三级缓存,这个是缓存工厂创建出来的bean的
      object = getCachedObjectForFactoryBean(beanName);
   }
   if (object == null) {
      // /若缓存没有则尝试创建
      // Return bean instance from factory.
      FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
      // Caches object obtained from FactoryBean if it is a singleton.
      if (mbd == null && containsBeanDefinition(beanName)) {
         mbd = getMergedLocalBeanDefinition(beanName);
      }
      boolean synthetic = (mbd != null && mbd.isSynthetic());
      object = getObjectFromFactoryBean(factory, beanName, !synthetic);
   }
   return object;
}


jvm里面通过Synthetic来标识是由自己的机制生成的类,用在这里标识这是Spring内部生成的Bean实例,不允许第三方改动。


进入到getObjectFromFactoryBean方法:


protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
   // 加果需要在工厂模式下维持单例的话
   if (factory.isSingleton() && containsSingleton(beanName)) {
      synchronized (getSingletonMutex()) {
         // 又见双重检查锁机制,尝试再从缓存中获取,防止多线程下可能有别的线程已完成该单例Bean的创建
         Object object = this.factoryBeanObjectCache.get(beanName);
         if (object == null) {
            // 调用工厂方法,创建Bean实例
            object = doGetObjectFromFactoryBean(factory, beanName);
            // Only post-process and store if not put there already during getObject() call above
            // (e.g. because of circular reference processing triggered by custom getBean calls)
            // 看看此时是否有别的线程先人一步创建好了Bean实例,如果是,则使用最先创建出来的以保证单例
            // 之所以这样做是因为factoryBean是用户自定义的,就有可能是异步模式的,即getObject可能是异步的
            Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
            if (alreadyThere != null) {
               object = alreadyThere;
            }
            else {
               // 如果是 Synthetic 的就不能使用后置处理器服务了
               if (shouldPostProcess) {
                  // 该Bean实例是否已经有别的线程在尝试创建,但是还没有进行后置处理
                  if (isSingletonCurrentlyInCreation(beanName)) {
                     // Temporarily return non-post-processed object, not storing it yet..
                     return object;
                  }
                  // 后置处理完成前,先加入缓存里锁定起来
                  beforeSingletonCreation(beanName);
                  try {
                     // 触发BeanPostProcessor,第三方框架可以在此用AOP来包装Bean实例
                     object = postProcessObjectFromFactoryBean(object, beanName);
                  }
                  catch (Throwable ex) {
                     throw new BeanCreationException(beanName,
                           "Post-processing of FactoryBean's singleton object failed", ex);
                  }
                  finally {
                     // 创建完成后,从缓存锁定的名字里清除
                     afterSingletonCreation(beanName);
                  }
               }
               if (containsSingleton(beanName)) {
                  // 将其放入缓存,证明单例已经创建完成了
                  this.factoryBeanObjectCache.put(beanName, object);
               }
            }
         }
         return object;
      }
   }
   else {
      // 如果不是单例,则直接创建并返回
      Object object = doGetObjectFromFactoryBean(factory, beanName);
      if (shouldPostProcess) {
         try {
            object = postProcessObjectFromFactoryBean(object, beanName);
         }
         catch (Throwable ex) {
            throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
         }
      }
      return object;
   }
}


先确保factory创建出来的是单例,如果是就先上锁,这里用到了双重锁检查机制,尝试再去factoryBeanObjectCache缓存里获取一遍,防止多线程下可能有别的线程已完成该单例Bean的创建


回到doGetBean,if块里的代码执行完了之后就会跳过else的代码块,然后再经过一系列检查之后就返回bean实例了


相关文章
|
1月前
|
Kubernetes Cloud Native 持续交付
Docker:轻量级容器化技术解析
Docker:轻量级容器化技术解析
|
1月前
|
缓存 监控 安全
告别缓存击穿!Go 语言中的防并发神器:singleflight 包深度解析
在高并发场景中,多个请求同时访问同一资源易导致缓存击穿、数据库压力过大。Go 语言提供的 `singleflight` 包可将相同 key 的请求合并,仅执行一次实际操作,其余请求共享结果,有效降低系统负载。本文详解其原理、实现及典型应用场景,并附示例代码,助你掌握高并发优化技巧。
196 0
|
3月前
|
存储 缓存 安全
Java 集合容器常见面试题及详细解析
本文全面解析Java集合框架,涵盖基础概念、常见接口与类的特点及区别、底层数据结构、线程安全等内容。通过实例讲解List(如ArrayList、LinkedList)、Set(如HashSet、TreeSet)、Map(如HashMap、TreeMap)等核心组件,帮助读者深入理解集合容器的使用场景与性能优化。适合准备面试或提升开发技能的开发者阅读。
66 0
|
5月前
|
弹性计算 Java Maven
从代码到容器:Cloud Native Buildpacks技术解析
Cloud Native Buildpacks(CNB)是一种标准化、云原生的容器镜像构建系统,旨在消除手动编写Dockerfile,提供可重复、安全且高效的构建流程。它通过分层策略生成符合OCI标准的镜像,实现应用与基础镜像解耦,并自动化依赖管理和更新。阿里云应用管理支持通过CNB技术一键部署应用至ECS,简化构建和运行流程。
|
6月前
|
算法 测试技术 C语言
深入理解HTTP/2:nghttp2库源码解析及客户端实现示例
通过解析nghttp2库的源码和实现一个简单的HTTP/2客户端示例,本文详细介绍了HTTP/2的关键特性和nghttp2的核心实现。了解这些内容可以帮助开发者更好地理解HTTP/2协议,提高Web应用的性能和用户体验。对于实际开发中的应用,可以根据需要进一步优化和扩展代码,以满足具体需求。
637 29
|
5月前
|
缓存 NoSQL Go
【LeetCode 热题100】146:LRU 缓存(详细解析)(Go语言版)
本文详细解析了力扣 146 题——LRU 缓存机制的实现方法。通过结合哈希表与双向链表,确保 `get` 和 `put` 操作均在 O(1) 时间内完成。哈希表用于快速查找,双向链表记录访问顺序,支持最近使用数据的高效更新与淘汰。代码以 Go 语言实现,结构清晰,涵盖核心操作如节点移动、插入与删除。此题为面试高频考点,适用于数据缓存、页面置换等场景,掌握后可加深对缓存策略的理解。
277 4
|
6月前
|
前端开发 数据安全/隐私保护 CDN
二次元聚合短视频解析去水印系统源码
二次元聚合短视频解析去水印系统源码
184 4
|
6月前
|
JavaScript 算法 前端开发
JS数组操作方法全景图,全网最全构建完整知识网络!js数组操作方法全集(实现筛选转换、随机排序洗牌算法、复杂数据处理统计等情景详解,附大量源码和易错点解析)
这些方法提供了对数组的全面操作,包括搜索、遍历、转换和聚合等。通过分为原地操作方法、非原地操作方法和其他方法便于您理解和记忆,并熟悉他们各自的使用方法与使用范围。详细的案例与进阶使用,方便您理解数组操作的底层原理。链式调用的几个案例,让您玩转数组操作。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
6月前
|
存储 前端开发 JavaScript
在线教育网课系统源码开发指南:功能设计与技术实现深度解析
在线教育网课系统是近年来发展迅猛的教育形式的核心载体,具备用户管理、课程管理、教学互动、学习评估等功能。本文从功能和技术两方面解析其源码开发,涵盖前端(HTML5、CSS3、JavaScript等)、后端(Java、Python等)、流媒体及云计算技术,并强调安全性、稳定性和用户体验的重要性。
|
6月前
|
负载均衡 JavaScript 前端开发
分片上传技术全解析:原理、优势与应用(含简单实现源码)
分片上传通过将大文件分割成多个小的片段或块,然后并行或顺序地上传这些片段,从而提高上传效率和可靠性,特别适用于大文件的上传场景,尤其是在网络环境不佳时,分片上传能有效提高上传体验。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~

推荐镜像

更多
  • DNS