Spring源码:Bean的生命周期(二)

这篇具有很好参考价值的文章主要介绍了Spring源码:Bean的生命周期(二)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

让我们继续讲解Spring的Bean实例化过程。在上一节中,我们已经讲解了Spring是如何将Bean定义加入到IoC容器中,并使用合并的Bean定义来包装原始的Bean定义。接下来,我们将继续讲解Spring的 getBean() 方法,特别是针对 FactoryBean 的解析。

getBean() 方法中,Spring还支持对 FactoryBean 进行特殊处理。FactoryBean 是一个能够生成Bean实例的工厂Bean,其定义了 getObject() 方法,返回的是一个由工厂Bean管理的对象实例。在使用 getBean() 方法获取 FactoryBean 类型的Bean时,Spring会首先获取 FactoryBean 的实例,然后调用其 getObject() 方法来获取由工厂Bean创建的实际Bean实例。

因此,在使用 getBean() 方法获取Bean实例时,我们需要注意是否需要对 FactoryBean 进行特殊处理。如果需要获取 FactoryBean 的实例而不是它所管理的对象实例,可以在Bean名称前加上 & 符号来进行标识。例如:&myFactoryBean 表示获取 myFactoryBean 的实例。但是博主看到第一篇源码写的篇幅确实有些长,可能对于大家伙的碎片化时间掌握的不是很充分,所以以后我会尽力控制篇幅长度,既保证逻辑的连续性也保证尽快可以看完,那么接下来开始进入正题getbean方法之FactoryBean解析。

FactoryBean

所有符合过滤条件的Bean在Spring解析后都会被转化为合并后的Bean定义。尽管Spring提供了 getBean() 方法用于获取Bean实例,但实际上它底层仍然使用 createBean() 方法来创建Bean实例。在创建Bean实例之前,Spring先对当前Bean定义进行判断,以确定其是否为 FactoryBean 类型:

public void preInstantiateSingletons() throws BeansException {  
   if (logger.isTraceEnabled()) {  
      logger.trace("Pre-instantiating singletons in " + this);  
   }  
  
   // Iterate over a copy to allow for init methods which in turn register new bean definitions.  
 // While this may not be part of the regular factory bootstrap, it does otherwise work fine.  List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);  
  
   // Trigger initialization of all non-lazy singleton beans...  
  for (String beanName : beanNames) {  
      // 获取合并后的BeanDefinition  
  RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);  
  
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {  
         if (isFactoryBean(beanName)) {  
            // 获取FactoryBean对象  
  Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);  
            if (bean instanceof FactoryBean) {  
               FactoryBean<?> factory = (FactoryBean<?>) bean;  
               boolean isEagerInit;  
               if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {  
                  isEagerInit = AccessController.doPrivileged(  
                        (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,  
                        getAccessControlContext());  
               }  
               else {  
                  isEagerInit = (factory instanceof SmartFactoryBean &&  
                        ((SmartFactoryBean<?>) factory).isEagerInit());  
               }  
               if (isEagerInit) {  
                  // 创建真正的Bean对象(getObject()返回的对象)  
  getBean(beanName);  
               }  
            }  
         }  
         else {  
            // 创建Bean对象  
  getBean(beanName);  
         }  
      }  
   }  
  
   // 所有的非懒加载单例Bean都创建完了后  
  // Trigger post-initialization callback for all applicable beans...  
  for (String beanName : beanNames) {  
      Object singletonInstance = getSingleton(beanName);  
      if (singletonInstance instanceof SmartInitializingSingleton) {  
         StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")  
               .tag("beanName", beanName);  
         SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;  
         if (System.getSecurityManager() != null) {  
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {  
               smartSingleton.afterSingletonsInstantiated();  
               return null;  
            }, getAccessControlContext());  
         }  
         else {  
            smartSingleton.afterSingletonsInstantiated();  
         }  
         smartInitialize.end();  
      }  
   }  
}

他的源码逻辑大致如下:

  1. Spring会根据 beanNamebean 定义 Map 中获取当前合并的 Bean 定义。
  2. Spring会对当前 Bean 定义进行判断,包括判断当前 Bean 是否为抽象的、是否为单例、是否懒加载,以及是否为 FactoryBean。如果是 FactoryBean,则会走 FactoryBean 的创建逻辑,否则会走单例 Bean 的创建逻辑。
  3. 当所有单例非懒加载的 Bean 创建完成后,Spring会遍历所有单例 Bean,判断其是否为 SmartInitializingSingleton 类型。如果是,则会自动调用 afterSingletonsInstantiated 方法。

isFactoryBean

由于创建 Bean 的逻辑比较复杂,其中包含了许多细节,因此,在这里我们特别提到了一个方法 isFactoryBean()。之所以要提到这个方法,是因为Spring支持使用 FactoryBean 来创建复杂对象。下面是该方法的主要源码:

public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {  
   String beanName = transformedBeanName(name);  
   Object beanInstance = getSingleton(beanName, false);  
   if (beanInstance != null) {  
      return (beanInstance instanceof FactoryBean);  
   }  
   // No singleton instance found -> check bean definition.  
  if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {  
      // No bean definition found in this factory -> delegate to parent.  
  return ((ConfigurableBeanFactory) getParentBeanFactory()).isFactoryBean(name);  
   }  
   return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));  
}

大致逻辑如下:

  1. transformedBeanName 的作用是不管传入的参数是 &××× 还是 ×××,都返回 ×××。这是因为Spring标记 FactoryBean 时使用 &××× 作为 FactoryBeanbeanName
  2. getSingleton 方法从单例池中获取 Bean 实例,如果该实例是 FactoryBean,则直接返回该实例。
  3. 如果 BeanFactory 中的 Bean 定义 Map 中不包含该 beanNameBean 定义,并且当前 BeanFactory 的父 BeanFactory 实现了 ConfigurableBeanFactory 接口,那么就需要查看当前父 BeanFactory 中是否有该实例,并且判断该实例是否为 FactoryBean。举个例子来说:
// 创建一个父Spring容器  
AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext();  
parent.register(AppConfig.class);  
parent.refresh();  
// 创建一个Spring容器  
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();  
applicationContext.setParent(parent);  
applicationContext.register(AppConfig1.class);  
applicationContext.refresh();  
UserService bean = applicationContext.getBean(UserService.class);  
bean.test();
  1. 如果并没有实例化出来的bean,那么对bean定义进行判断。
protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) {  
   Boolean result = mbd.isFactoryBean;  
   if (result == null) {  
      // 根据BeanDefinition推测Bean类型(获取BeanDefinition的beanClass属性)  
  Class<?> beanType = predictBeanType(beanName, mbd, FactoryBean.class);  
      // 判断是不是实现了FactoryBean接口  
  result = (beanType != null && FactoryBean.class.isAssignableFrom(beanType));  
      mbd.isFactoryBean = result;  
   }  
   return result;  
}

注释也基本写好了,基本上就是根据BeanDefinition推测Bean类型(获取BeanDefinition的beanClass属性),再根据bean类型判断是不是实现了FactoryBean接口,然后返回判断结果。

SmartFactoryBean

getBean 方法中,我们可以获取 FactoryBean 的实例并返回。接下来的步骤是判断当前的 FactoryBean 是否实现了 SmartFactoryBean 接口。需要注意的是,SmartFactoryBeanFactoryBean 接口的一个子接口。虽然我们在实现 FactoryBean 接口时不必实现 SmartFactoryBean 接口,但是如果实现了 SmartFactoryBean 接口,那么在创建 FactoryBean 时就会调用 getObject 方法返回实例。正常情况下,只有当容器启动完成后才会调用 getObject 方法。如果我们想在初始化时就调用,可以这样实现:

@Component  
public class UserFactory implements SmartFactoryBean {  
 
   @Override  
  public Object getObject() throws Exception {  
      return new User();  
   }  
  
   @Override  
  public Class<?> getObjectType() {  
      return User.class;  
   }  
  
   @Override  
  public boolean isEagerInit() {  
      return true;  
   }  
}

结语

FactoryBean 和 BeanFactory 是两个不同的概念。前者是一个接口,我们可以在实现该接口时通过调用 getObject 方法来返回实例,同时 FactoryBean 本身也是一个实例。后者是 Spring 容器的工厂,通过其中的 bean 定义 Map 一个一个地实例化我们通过注解等方式注入进去的 bean 工厂。在判断 FactoryBean 时,如果当前 BeanFactory 中没有对应的 bean 定义,那么就会去父容器中寻找相应的 bean 定义并进行判断。如果我们的类实现了 SmartFactoryBean 接口,那么它将会在 Spring 容器启动时就会调用 getObject 方法创建实例。接下来,我们将分几个小节来讲解 getBean 方法是如何实例化 bean 的,因为篇幅过长会影响读者的注意力和学习效果。文章来源地址https://www.toymoban.com/news/detail-431046.html

到了这里,关于Spring源码:Bean的生命周期(二)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring源码:bean的生命周期(一)

    本节将正式介绍Spring源码细节,将讲解Bean生命周期。请注意,虽然我们不希望过于繁琐地理解Spring源码,但也不要认为Spring源码很简单。在本节中,我们将主要讲解Spring 5.3.10版本的源代码。如果您看到的代码与我讲解的不同,也没有关系,因为其中的原理和业务逻辑基本相

    2024年02月02日
    浏览(37)
  • Spring之Bean生命周期源码解析

    ClassPathBeanDefinitionScanner.java ClassPathScanningCandidateComponentProvider.java 通过组件索引寻找 这里的 componentsIndex 在初始化的时候会尝试解析 META-INF/spring.components 文件中的配置信息 把断点打在 ClassPathScanningCandidateComponentProvider 的 setResourceLoader 方法上调试可以看到堆栈 可以看到,的确

    2024年02月11日
    浏览(43)
  • 【Spring】Spring之Bean生命周期源码解析

    什么是bean的生命周期 是指bean在spring中是如何生成,如何销毁的; spring创建对象的过程,就是IOC(控制反转)的过程; JFR Java Flight Record,java飞行记录,类似于飞机的黑匣子,是JVM内置的基于事件的JDK监控记录框架,主要用于问题定位和持续监控; 入口代码: Spring启动的时

    2024年02月15日
    浏览(46)
  • 【框架源码】Spring源码解析之Bean生命周期流程

    观看本文前,我们先思考一个问题,什么是Spring的bean的生命周期?这也是我们在面试的时候,面试官常问的一个问题。 在没有Spring之前,我们创建对象的时候,采用new的方式,当对象不在被使用的时候,由Java的垃圾回收机制回收。 而 Spring 中的对象是 bean,bean 和普通的 J

    2024年02月09日
    浏览(45)
  • 【深入Spring源码解析:解密Bean的生命周期】

    Spring是Java企业级应用开发领域的一颗明星,它提供了很多方便开发人员的工具和思想。在分布式系统中,Spring的分布式远程协作方案,比如REST、Web服务以及消息传递等,也是不可或缺的。 你知道吗?在我们使用Spring时,容器中存放的所有对象,在Spring启动的时候就完成了实

    2024年02月05日
    浏览(40)
  • 【Spring专题】Spring之Bean的生命周期源码解析——上(扫描生成BeanDefinition)

    由于Spring源码分析是一个前后联系比较强的过程,而且这边分析,也是按照代码顺序讲解的,所以不了解前置知识的情况下,大概率没办法看懂当前的内容。所以,特别推荐看看我前面的文章(自上而下次序): Spring底层核心原理解析——引导篇【学习难度: ★★☆☆☆ 】

    2024年02月13日
    浏览(40)
  • 【Spring专题】Spring之Bean的生命周期源码解析——阶段一(扫描生成BeanDefinition)

    由于Spring源码分析是一个前后联系比较强的过程,而且这边分析,也是按照代码顺序讲解的,所以不了解前置知识的情况下,大概率没办法看懂当前的内容。所以,特别推荐看看我前面的文章(自上而下次序): Spring底层核心原理解析——引导篇【学习难度: ★★☆☆☆ 】

    2024年02月13日
    浏览(44)
  • 【Spring专题】Spring之Bean的生命周期源码解析——阶段二(IOC之实例化)

    由于Spring源码分析是一个前后联系比较强的过程,而且这边分析,也是按照代码顺序讲解的,所以不了解前置知识的情况下,大概率没办法看懂当前的内容。所以,特别推荐看看我前面的文章(自上而下次序): Spring底层核心原理解析——引导篇【学习难度: ★★☆☆☆ 】

    2024年02月13日
    浏览(55)
  • 【Spring专题】Spring之Bean的生命周期源码解析——阶段二(二)(IOC之属性填充/依赖注入)

    由于Spring源码分析是一个前后联系比较强的过程,而且这边分析,也是按照代码顺序讲解的,所以不了解前置知识的情况下,大概率没办法看懂当前的内容。所以,特别推荐看看我前面的文章(自上而下次序): Spring底层核心原理解析【学习难度: ★★☆☆☆ 】 手写简易

    2024年02月12日
    浏览(39)
  • bean的生命周期(最全最细讲解)

    其定义为: 从对象的创建到销毁的过程。 而Spring中的一个Bean从开始到结束经历很多过程,但总体可以分为 六个阶段Bean定义、实例化、属性赋值、初始化、生存期、销毁 。 1.首先我们来创建一个包,在包中创建一个Orders的对象,然后在对象中创建一个无参构造方法.... 2.Sp

    2023年04月22日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包