Spring源码分析之Bean的创建过程详解(一)

简介: Spring源码分析之Bean的创建过程详解

前文传送门:

  1. Spring源码分析之预启动流程
  2. Spring源码分析之BeanFactory体系结构
  3. Spring源码分析之BeanFactoryPostProcessor调用过程详解

本文内容:

  1. 在IOC中,是如何通过beanDefition创建出一个bean的?
  2. 各BeanPostProcessor在这过程中扮演的角色,调用时机?

话不多说,直接正题走起,上图!

下面是bean创建过程的大致流程图,本文将以图中顺序进行逐步源码分析,小伙伴亦可与图中流程边对照边品食

原矢量图地址:https://www.processon.com/view/link/5f6174431e08531edf3134fb

我们知道,在Spring IOC前段部分有注册了一系列的BeanPostProcessor,在Bean的创建过程中,就将要使用到他们了,下面我给大家一一列出

  • AutowiredAnnotationBeanPostProcessor:在new AnnotatedBeanDefinitionReader时注册
  • CommonAnnotationBeanPostProcessor: 在new AnnotatedBeanDefinitionReader时注册
  • ApplicationContextAwareProcessor: 在prepareBeanFactory时注册
  • ApplicationListenerDetector: 在prepareBeanFactory时注册
  • ImportAwareBeanPostProcessor: 在配置类后置处理器调用postProcessBeanFactory注册
  • BeanPostProcessorChecker:在registerBeanPostProcessors时注册

以上就是Spring中内置的所有BeanPostProcessor了

同样,我们先从最开始的入口refresh开始分析

public void refresh(){
  //....省略前面部分
  // 实例化剩余的单例bean
  finishBeanFactoryInitialization(beanFactory);
}

finishBeanFactoryInitialization

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory){
  // 将所有非懒加载的bean加载到容器中
  beanFactory.preInstantiateSingletons();
}

循环我们之前注册的所有beanDefinition,一个个的进行调用getBean注册到容器中

public void preInstantiateSingletons(){
  // 循环所有beanDefinition
  for (String beanName : beanNames) {
    // 将beanDefinition转化为RootBeanDefinition
    RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
    // 不是抽象类并且是单例并且非懒加载
    if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
      // 是否为工厂bean
      if (isFactoryBean(beanName)) {
        // 由于是以&开头获取bean,这里返回的是一个工厂bean,并且不会调用getObject方法
        Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
        if (bean instanceof FactoryBean) {
          // 判断是否要立即初始化bean
          FactoryBean<?> factory = (FactoryBean<?>) bean;
          boolean isEagerInit = (factory instanceof SmartFactoryBean &&
                           ((SmartFactoryBean<?>) factory).isEagerInit());
          if (isEagerInit) {
            // 以为&开头的方式再获取一次,此时会调用FactoryBean的getObject()方法
            getBean(beanName);
          }
        }
      }
      else {
        // 不是FactoryBean,直接使用getBean进行初始化
        getBean(beanName);
      }
    }
  }
}

接下来就是Spring的常规操作,调用do开头的doGetBean

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

以下为doGetBean中获取单例bean的逻辑

// 转化beanName 如果是以&开头则去除,如果有别名则获取别名
String beanName = transformedBeanName(name);
// 尝试从三级缓存中获取bean
Object sharedInstance = getSingleton(beanName);
// 是否从缓存中获取到了bean
if (sharedInstance != null && args == null) {
  // 如果是工厂类且name不以&开头,则调用工厂类的getObject()
  // 其他情况返回原对象
  bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}

getSingleton

public Object getSingleton(String beanName) {
    return getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 从单例缓存池中获取
    Object singletonObject = this.singletonObjects.get(beanName);
    // 获取不到,判断bean是否正在创建
    // 如果是正在创建,2种情况 1.多个线程在创建bean 2.发生循环依赖
    // 如果是多个线程,则由于同步锁阻塞于此
    // 循环依赖的问题较为复杂,将在下章详细分析
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      synchronized (this.singletonObjects) {
        // 从早期对象缓存池中获取
        singletonObject = this.earlySingletonObjects.get(beanName);
        if (singletonObject == null && allowEarlyReference) {
          // 从三级缓存中获取单例工厂
          ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
          if (singletonFactory != null) {
            // 调用回调方法获取早期bean
            singletonObject = singletonFactory.getObject();
            // 将早期对象放到二级缓存,移除三级缓存
            this.earlySingletonObjects.put(beanName, singletonObject);
            this.singletonFactories.remove(beanName);
          }
        }
      }
    }
    return singletonObject;
  }

getObjectForBeanInstance

protected Object getObjectForBeanInstance(
      Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
    // 判断name是否以&开头,是则直接返回该FactoryBean
    /*public static boolean isFactoryDereference(@Nullable String name) {
        return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
    }*/
    if (BeanFactoryUtils.isFactoryDereference(name)) {
      return beanInstance;
    }
    // 不是工厂bean直接返回原对象
    if (!(beanInstance instanceof FactoryBean)) {
      return beanInstance;
    }
    // 尝试从缓存中获取,保证多次从工厂bean获取的bean是同一个bean
    object = getCachedObjectForFactoryBean(beanName);
    if (object == null) {
      FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
      boolean synthetic = (mbd != null && mbd.isSynthetic());
      // 从FactoryBean获取对象
      object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    return object;
  }

getObjectFromFactoryBean的代码摘取片段

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess){
  // 获取bean,调用factoryBean的getObject()
  object = doGetObjectFromFactoryBean(factory, beanName);
}
private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName){
  object = factory.getObject();
}

以上为从缓存中获取到bean,处理FactoryBean的逻辑,接下来我们看看实际创建bean的过程

以下为续接上面doGetBean中未从缓存中获取到bean的逻辑

// 如果有被@DependsOn标记,先创建DependsOn的bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
  for (String dep : dependsOn) {
    registerDependentBean(dep, beanName);
    getBean(dep);
  }
}
// 单例bean
if (mbd.isSingleton()) {
  // 开始创建bean
  sharedInstance = getSingleton(beanName, () -> {
    // 真正创建bean
    return createBean(beanName, mbd, args);
  });
  // 如果是工厂类且name不以&开头,则调用工厂类的getObject()
  // 其他情况返回原对象
  bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

getSingleton,此方法为重载方法,与从缓存中获取bean并非同一个

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "Bean name must not be null");
    // 开始创建bean时加锁,注意这个锁的同步对象与从缓存中获取时锁的同步对象相同
    synchronized (this.singletonObjects) {
      // 再次从缓存中获取,有直接返回,出现有的情况
      // 1.线程一正在创建A实例,线程二尝试获取,被同步锁阻塞
      // 2.线程一创建完毕,线程二进入同步代码块,从缓存中获取直接返回
      Object singletonObject = this.singletonObjects.get(beanName);
      if (singletonObject == null) {
        // 标记正在创建中
        beforeSingletonCreation(beanName);
        boolean newSingleton = false;
        try {
          // 调用回调函数获取到bean
          singletonObject = singletonFactory.getObject();
          newSingleton = true;
        }
        finally {
          // 清理状态
          afterSingletonCreation(beanName);
        }
        if (newSingleton) {
          // 将创建的bean添加到单例缓存池中,并移除二三级缓存
          addSingleton(beanName, singletonObject);
        }
      }
      return singletonObject;
    }
  }

createBean,终于开始创建bean了~

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){
  // 第一次调用bean后置处理器,在bean实例化之前的进行处理
  // Spring内置的后置处理器中,无相关实现
  // 可使用自定义的后置处理器在这里进行中止bean的创建过程操作
  Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
  if (bean != null) {
    // 如果自定义的后置处理器返回了bean,则直接return,bean的创建过程于此中断
    return bean;
  }
  // 进行创建bean
  Object beanInstance = doCreateBean(beanName, mbdToUse, args);
}
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){
  // 实例化bean 第二次调用bean后置处理器,用于获取bean的有参构造器
  instanceWrapper = createBeanInstance(beanName, mbd, args);
  // 第三次 处理beanDefinition的元数据信息
  applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
  // 是否允许暴露早期对象
  boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                                    isSingletonCurrentlyInCreation(beanName));
  // 第四次 用于获取早期对象时的处理
  // 将获取早期对象的回调方法放到三级缓存中
  addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
  // 第五、六次,填充属性 可使用的方式 byName byType @Resource @Value @Autowired @Inject
  populateBean(beanName, mbd, instanceWrapper);
  // 第七、八次,初始化
  exposedObject = initializeBean(beanName, exposedObject, mbd);
  // 第九次 判断bean是否有销毁方法,有则将bean注册到销毁集合中,用于容器关闭时使用
  registerDisposableBeanIfNecessary(beanName, bean, mbd);
  // 返回创建好的bean
  return exposedObject;
}

你以为这就结束了?

接下来我们就来看看这里后置处理器到底做了什么吧

由于第一次调用并未有任何处理,我们从第二次调用开始分析


目录
相关文章
|
3天前
|
监控 Java 应用服务中间件
Spring Boot整合Tomcat底层源码分析
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置和起步依赖等特性,大大简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是其与Tomcat的整合。
19 1
|
10天前
|
缓存 Java Spring
实战指南:四种调整 Spring Bean 初始化顺序的方案
本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
实战指南:四种调整 Spring Bean 初始化顺序的方案
|
1月前
|
XML Java 数据格式
Spring从入门到入土(bean的一些子标签及注解的使用)
本文详细介绍了Spring框架中Bean的创建和使用,包括使用XML配置文件中的标签和注解来创建和管理Bean,以及如何通过构造器、Setter方法和属性注入来配置Bean。
66 9
Spring从入门到入土(bean的一些子标签及注解的使用)
|
18天前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
28 1
|
19天前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
25 1
|
1月前
|
缓存 JavaScript Java
Spring之FactoryBean的处理底层源码分析
本文介绍了Spring框架中FactoryBean的重要作用及其使用方法。通过一个简单的示例展示了如何通过FactoryBean返回一个User对象,并解释了在调用`getBean()`方法时,传入名称前添加`&`符号会改变返回对象类型的原因。进一步深入源码分析,详细说明了`getBean()`方法内部对FactoryBean的处理逻辑,解释了为何添加`&`符号会导致不同的行为。最后,通过具体代码片段展示了这一过程的关键步骤。
Spring之FactoryBean的处理底层源码分析
|
28天前
|
Java 测试技术 Windows
咦!Spring容器里为什么没有我需要的Bean?
【10月更文挑战第11天】项目经理给小菜分配了一个紧急需求,小菜迅速搭建了一个SpringBoot项目并完成了开发。然而,启动测试时发现接口404,原因是控制器包不在默认扫描路径下。通过配置`@ComponentScan`的`basePackages`字段,解决了问题。总结:`@SpringBootApplication`默认只扫描当前包下的组件,需要扫描其他包时需配置`@ComponentScan`。
|
2月前
|
XML Java 数据格式
spring复习02,xml配置管理bean
详细讲解了Spring框架中基于XML配置文件管理bean的各种方式,包括获取bean、依赖注入、特殊值处理、属性赋值、集合类型处理、p命名空间、bean作用域及生命周期和自动装配。
spring复习02,xml配置管理bean
|
16天前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
21 0
|
1月前
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细解析Spring Bean的生命周期及其核心概念,并深入源码分析。Spring Bean是Spring框架的核心,由容器管理其生命周期。从实例化到销毁,共经历十个阶段,包括属性赋值、接口回调、初始化及销毁等。通过剖析`BeanFactory`、`ApplicationContext`等关键接口与类,帮助你深入了解Spring Bean的管理机制。希望本文能助你更好地掌握Spring Bean生命周期。
72 1