Spring核心源码(四)对象实例化和对象初始化

​Spring 创建对象

在上一章我们对invokeBeanFactoryPostProcessors的重要部分进行了详细的介绍,总算到了我们的Spring创建对象的过程了,本章会接着前面的refresh进行续写。

registerBeanPostProcessors(beanFactory)

这个方法的特性和invokeBeanFactoryPostProcessors(beanFactory);其实差不太多,也是对后置处理器的一些操作,但这个方法的重量缺少了很多,相信读者有了invokeBeanFactoryPostProcessors(beanFactory);的经验应该能够自行理解其基本意义。

initMessageSource();

初始化国际化资源,这里只是对一些资源加载的方式进行规范。

initApplicationEventMulticaster();

创建ApplicationEventMulticaster这么一个类,这个类是事件操控的核心,我们先跳过,这里不会影响整体Bean初始化

onRefresh();

空方法

registerListeners

注册监听器

finishBeanFactoryInitialization(beanFactory)

总算到我们真正创建Bean的核心方法了,通过这个方法的名字就可以猜到,这就是我们Spring用来创建对象的核心方法,如果不相信的话我们在这里调试一下,首先看第一张图

image

singletonObjects就是我们的实例对象,这里不同的Spring版本可能singletonObjects所在的类会有一些区别,那么如果singletonObjects数量发生改变说创建对象就是在这里实现的,我们调试一下

image

 

image

可以看到singletonObjects的数量确实增加了几个,而且这几个就是我们所创建的,那么我们就开始对其进行分析,在对finishBeanFactoryInitialization深度分析时,笔者只会对一些核心点进行解释说明,因为内容确实太多,有些比较特殊的我就一笔带过,话不多说看代码

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // 这里不知道CONVERSION_SERVICE_BEAN_NAME有什么用
    if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
        beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
      beanFactory.setConversionService(
          beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
    }
​
    // Register a default embedded value resolver if no bean post-processor
    // (such as a PropertyPlaceholderConfigurer bean) registered any before:
    // at this point, primarily for resolution in annotation attribute values.
    //检查Spring中是否存在类型转换
    if (!beanFactory.hasEmbeddedValueResolver()) {
      beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
    }
    // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
    String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
    for (String weaverAwareName : weaverAwareNames) {
      getBean(weaverAwareName);
    }
​
    // 禁止使用临时类加载器进行类型匹配
    beanFactory.setTempClassLoader(null);
​
    // Allow for caching all bean definition metadata, not expecting further changes.
    //允许缓存所有的bean的定义数据
    beanFactory.freezeConfiguration();
​
    // Instantiate all remaining (non-lazy-init) singletons.
    //重点,准备bean实例
    beanFactory.preInstantiateSingletons();
  }

注释比较详细,这里其实没做什么事情,核心方法是beanFactory.preInstantiateSingletons();我们点进去

  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.
    //拿到所有的bd名字
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
​
    // Trigger initialization of all non-lazy singleton beans...
    //循环并判断是不是不是懒加载的,是不是FactoryBean,然后对bd进行bean创建
    for (String beanName : beanNames) {
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
        if (isFactoryBean(beanName)) {
          Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
          if (bean instanceof FactoryBean) {
            final 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) {
              getBean(beanName);
            }
          }
        }
        else {
          getBean(beanName);
        }
      }
    }
​
    // Trigger post-initialization callback for all applicable beans...
    for (String beanName : beanNames) {
      Object singletonInstance = getSingleton(beanName);
      if (singletonInstance instanceof SmartInitializingSingleton) {
        final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
        if (System.getSecurityManager() != null) {
          AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            smartSingleton.afterSingletonsInstantiated();
            return null;
          }, getAccessControlContext());
        }
        else {
          smartSingleton.afterSingletonsInstantiated();
        }
      }
    }
  }

这里首先执行RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);将我们的BeanDefinition合并,最后都采用RootBeanDefinition声明,然后判断是不是单例对象,是不是FactoryBean,如果不是就会进入getBean(beanName);我们在跟进

image

这里为什么是GetBean而不是创建对象,其实 Spring在很多地方都会获取对象,所以不可能每次获取都是创建对象,而应该是先查询有没有,再创建就像我们使用的缓存技术一样。我们继续

image

进入这句代码:Object sharedInstance = getSingleton(beanName);

image

这里先简单分析下,如果获取的对象是没有完全创建的,那么的singletonObject为空,isSingletonCurrentlyInCreation(beanName)也会为false那么判断会退出,记住这个isSingletonCurrentlyInCreation,然后我们继续

image

这些都不重要,我们往下看----

Bean实例化

image

这里的return createBean(beanName, mbd, args);是表达式语法,其实就是一个回调方式,然后我们调试进入getSingleton,

image

这里会做一些判断,如果没有实例化这个对象那么
它就会执行这段代码beforeSingletonCreation(beanName);我们看看这段代码做了什么

image

他会将我们的对象标识为正在创建,记住这个标识

image

然后再往下走回走到singletonObject = singletonFactory.getObject();

image

可以看到这里产生回调,不熟悉函数式的朋友们可以先忽略它,我们进入createBean(beanName, mbd, args);

image

 

image

前面都不重要,可以看到创建对象的代码在这一行Object beanInstance =

doCreateBean(beanName, mbdToUse, args);笔者这里再啰嗦一下这段代码Object bean =resolveBeforeInstantiation(beanName, mbdToUse);

image

这里笔者认为设计的有些累赘了,它的目的其实就是如果程序员定义的对象实现这个InstantiationAwareBeanPostProcessor接口,那么Spring就会认为这个对象不需要经过Spring的完整生命周期,需要脱离Spring管理的意思,然后直接return掉,但我想Spring可能也是为了扩展的开放性吧,毕竟Spring的设计考虑的十分周全。好了,我们回到代码Object beanInstance = doCreateBean(beanName, mbdToUse, args);

image

这里定义了一个instanceWrapper,读者可以将其当做一个有一些功能的对象,然后进入instanceWrapper = createBeanInstance(beanName, mbd, args);

image

这里主要是获取class类型,然后判断是不是FactoryMethod创建对象,如果不是就继续往下:

image

这里其实是一种缓存技术,如果我们在前面已经确认了这个类的构造器是什么,那么久不会再进行下文的构造器策略,直接调用构造器方法,当然我们这里暂时没有。

image

这里是Spring对实例构造器的一个策略,我们都知道一个类创建一个对象无非就两种情况,调用有参构造函数或者无参构造函数,那么我们先从无参构造说起,看下图

image

假如我们的ctors为空 也就是说我们的对象是用的无参构造,那么会执行到return instantiateBean(beanName, mbd);,我们跟踪此代码

image

在跟踪beanInstance =getInstantiationStrategy().instantiate(mbd, beanName, parent);->return BeanUtils.instantiateClass(constructorToUse);->

image

最终可以看到我们的反射代码newInstance。介绍完无参构造器创建对象后,我们开始探讨第二种有参构造创建对象的方式,回到IDEA,首先我们对User1类新增一个有参构造器,

image

然后我们开始debug调试,我们以User1类作为调试类

image

然后进入determineConstructorsFromBeanPostProcessors方法

image

这里会拿出很多后置处理器,但前面的基本都是默认实现,真正干活的是这个类AutowiredAnnotationBeanPostProcessor
然后进入:

image

前面的方法是检查是否存在LOCKUP方法,我们这里没有执行下一步

image

这里也没做什么事情,只是想从缓存中拿出有没有确定好的构造器,后面会获取所有构造方法,判断方法是不是加了@Awtowire注解,基本都会跳过,我们直接跳到核心代码

image

这里其实就是确认构造器,从我们的断点来看,当我们拿到的构造函数只有一个,且参数大于0,从我们目前的情况来看是符合的,那么就会返回我们构造器。拿到构造器后我们再看

image

我们会拿到我们所创建的构造器,那如果我们换一种方式采用多个构造器

image

我们调试发现

image

返回的值为null,其实这也很好理解,在没有指定某个构造器primary时,如果我们创建多个构造器,Spring不知道如何决策,就只执行默认构造器

image

,在上文我们对无参构造的方式进行了介绍,现在我们对有参构造进行说明

image

autowireConstructor()->autowireConstructor();
这里我们思考下如何用有参构造的方式创建对象,首先是不是确定我们的类,其次是不是需要确定构造器,然后我们还需要确定参数的值是什么,那么下面的操作就是确定参数的值到底是什么,我们回到IDEA:

image

这里没什么需要多说的

image

这里看有没有缓存,显然我们没有

image

这里的代码个人认为Spring可能为了防止其他地方复用这段代码,所以判断构造器是不是为空

image

这里autowiring肯定不会false,然后进入有参构造十分关键的代码

image

通过方法名我们都能大概猜出来这里就是获取有参构造传入的参数值,前面我们说过,确定构造器还需要构造参数的值才能成功创建一个对象,那么我们看这个代码能否获取参数值

image

很显然这里并没有获取,道理很简单,因为我们并没有对User1类指定构造器参数值,如果我们继续运行下去,Spring会抛出异常,表示无法创建这个类,这样很好说明,我们想要使用有参构造创建对象,确定没有给定参数值,这必然会报错,

image

那么怎样才能获取参数值呢,这里笔者会采用两种方式:第一种方式笔者会改变Spring源码

image

然后我们再次运行

image

,发现已经有值,然后User1类会创建对象成功,当然我们去改变源码是不是不太合适啊,所以采用第二种方式后置处理器,代码如下:

image

依旧可以实现有参构造的方式,

读到这里,读者是否有些恍然大悟,领略到了笔者前面提出的Spring的后置处理器的作用和设计的精妙,这样就可以实例化一个对象了,当然这还没有完,Spring还会对其他特别的有参构造进行解析,因为设计思想较为复杂,读者有兴趣可以自行深入了解,那么我们的对象实例化就算结束了,回到IDEA,

image

这里我们返回了我们的对象。

Bean初始化

image

在创建完对象后,Spring将会对象进行初始化,我们跟踪applyMergedBeanDefinitionPostProcessors这段代码:

image

可以看到这又是循环后置处理器,获取属于MergedBeanDefinitionPostProcessor,然后我们继续跟踪bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);在查看这个方法到底会执行哪些处理器,

image

我们在对其中之一后置处理器点开

image

 

image

其实这里的处理器就是对我们Spring的生命周期的处理,但这里并不会执行,而是采用元信息的方式将它保存起来,好了,我们继续往下看

image

前面的代码不重要,我们直接看到addSingletonFactory(beanName, () ->
getEarlyBeanReference(beanName, mbd, bean));

image

这里会有四个集合,第一个集合是singletonObjects存放单例Bean的,第二个singletonFactories
存放的是ObjectFactory工厂Bean,这个ObjectFactory个人认为和Bean并无太大区别,直接间接存取而已,第三个earlySingletonObjects是提前存储的对象,最后一个registeredSingletons存放的是BeanName,用来解决排序问题,好了我们继续

image

接下来可以看到Spring的属性注入的核心代码populateBean(beanName, mbd,
instanceWrapper);,在对这段代码分析之前,我们先修改一下我们的工程,首先将User2改成

image

再将User1改成

image

这条调整的目的是为了演示循环依赖,好了,
然后我们重新debug

image

这里先对User1属性注入,我们点进去

image

这里又有对后置处理器的处理,这里后置处理器的作用是如果你实现了InstantiationAwareBeanPostProcessors的postProcessAfterInstantiation方法,那么Spring会认为你牛逼,你要自己初始化,那我就中断这个Bean的后续一切操作,就等于脱离Spring的生命周期管理,其实这也是可以想到的,不一定所有的对象都是需要Spring帮我们处理,这里Spring的设计考虑的十分周全,我们回到IDEA

image

这里有一个重要的属性叫AutowireMode,为什么说他重要,我们会在Spring-Mybatis章节详细说明,这里先跳过,因为我们默认的是NO,然后我们进入这里

image

看方法名能够大概猜到这里就是属性注入的关键,我们断点

image

然后我们直接跳到AutowiredAnnotationBeanPostProcessor,进入这个方法PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);首先获取我们的InjectionMetadata,注入需要的元数据

image

然后->metadata.inject(bean, beanName, pvs);->element.inject(target, beanName, pvs);

然后我们先看最后一行代码

image

field.set(bean, value);懂反射的小伙伴们都知道,我们可以通过Field类对一个类的对象属性赋值,所以Spring默认也采用的这种方式,那么我们现在有了类,缺少value,而这个value在元数据中已经显示User2类,所以我们需要拿到User2的对象才行,回到IDEA上面的代码,其中有一行

image

然后我们跟踪下resolveDependency->doResolveDependency->descriptor.resolveCandidate

image

最终又回到了getBean,也就是说Spring会从工厂里拿,而这个时候我们的工厂并没有创建它,所以User2创建对象后依旧会进行进入属性注入的方法

image

这个时候我们跳到了User2的属性注入方法,然后一样User2里面有User1这个类,所以又会去获取User1的对象,但是我们的User1并没有创建完成,属于创建中的状态,那么Spring是如何解决的呢?我们继续跟踪代码

image

这里的代码是我们先创建了User1然后属性注入user2,这时工厂没有User2对象,于是创建User2,User2创建完后开始对内部的属性user1注入,这时会跳到上图,然后我们再跟踪进去

image

singletonObject == null 目前是为空的,因为我们的user1还在创建中,然而这一行代码我们运行isSingletonCurrentlyInCreation(beanName)

image

返回的是true,还记我们创建对象时会将对象标识为正在创建吗?这里就起到了效果,那么if会成立,这个时候就会从我们的ObjectFactory获取,在上文提到过ObjectFactory是间接存取,

image

随后User2拿到了User1的对象,然后User1也会拿到User2的对象因此解除循环依赖,创建对象成功,最后

image

这里会获取我们前文存储的生命周期元数据,并执行

image

 

image

我们用一张图回顾下我们的循环依赖

 

image

目前对Spring的整体核心源码基本已经告一段落,后面会对AOP、Spring-Mybatis、事物、数据来源、事件等知识结合面试题的方式进行嵌套描述。

文章来源微信公众号《七天0》

下一章节,笔者会对Spring-Mybatis核心设计思想进行解析

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring框架是一个应用程序框架,主要目的是简Java开发。Spring容器是Spring框架的核心,它负责管理应用程序中的所有对象Spring容器在启动时会创建所有需要的对象,并将它们初始化和配置好,最后将它们放入容器中,供应用程序使用。Spring容器的生命周期包括实例、属性赋值、初始化、销毁等几个阶段。 1. 实例 Spring容器在启动时会读取配置文件,找到需要创建的对象,然后使用Java反射机制创建这些对象Spring支持多种实例方式,包括构造方法实例、工厂方法实例、静态工厂方法实例等。 2. 属性赋值 Spring容器在创建对象后,会自动将对象的属性赋值。属性赋值有两种方式:使用setter方法和使用注解。使用setter方法时,Spring容器会调用对象的setter方法,将配置文件中的属性值赋值给对象的属性。使用注解时,需要在属性上添加相应的注解,Spring容器会自动将配置文件中的属性值赋值给注解标注的属性。 3. 初始化 Spring容器在完成属性赋值后,会调用对象初始化方法。初始化方法可以使用注解@PostConstruct或实现接口InitializingBean来定义。在初始化方法中,可以进行一些额外的初始化工作。 4. 销毁 Spring容器在关闭时,会调用对象的销毁方法。销毁方法可以使用注解@PreDestroy或实现接口DisposableBean来定义。在销毁方法中,可以进行一些额外的销毁工作。 下面是Spring容器实例和属性赋值的码示例: ```java public class Student { private String name; private int age; public Student() { System.out.println("Student被创建了"); } public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } public void init() { System.out.println("Student被初始化了"); } public void destroy() { System.out.println("Student被销毁了"); } } public class StudentService { private Student student; public StudentService() { System.out.println("StudentService被创建了"); } public void setStudent(Student student) { this.student = student; } public void init() { System.out.println("StudentService被初始化了"); } public void destroy() { System.out.println("StudentService被销毁了"); } } public class Main { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); StudentService studentService = (StudentService) context.getBean("studentService"); System.out.println("学生姓名:" + studentService.getStudent().getName()); System.out.println("学生年龄:" + studentService.getStudent().getAge()); } } ``` 在上面的代码中,Student类表示学生对象,StudentService类表示学生服务,Main类是启动Spring容器的入口。在Spring配置文件中,定义了一个id为"student"的学生对象和一个id为"studentService"的学生服务对象,学生服务对象依赖于学生对象。在初始化时,Spring容器会自动为学生对象和学生服务对象赋值,并调用它们的初始化方法。在销毁时,Spring容器会调用它们的销毁方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值