spring bean的创建过程一

本文深入探讨Spring MVC中的ConversionService配置方法及使用,包括自定义转换器的实现和注册过程。同时分析FactoryBean的工作原理,详细介绍其在Spring容器中的实例化流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本章主要讲解三个知识点

1 ConversionService相关知识

2 getMergedLocalBeanDefinition方法分析

3 FactoryBean源码分析

下面开始讲bean的创建过程,首先定位到源码:

1 先讲一下ConversionService

Spring在convert.converter中定义了3中类型的转换器接口,实现其中任何一个接口,然后将其注入到ConversionServiceFactoryBean当中就可以使用

Converter<S,T>,是Spring中最简单的接口,该接口中只有一个方法:T convert(S source)。该方法负责将S类型的对象转换为T类型的对象。

  • ConverterFactory<S,R> 如果希望将一种类型的对象转换为另一种类型及其子类对象,比如将String 转换为Number以及Number的子类Integer,Double等类型,就需要一系列的Converter。ConverterFactory接口的作用就是将相同系列多个Converter封装在一起,该接口中只有一个方法: Converter <S,T> getConverter(Class<T> targetType)。其中S为转换的源类型,R为目标类型的基类,T为R的子类,即为要转换目标类。
  • GenericConverter接口会根据源类对象以及目标对象的上下文信息进行类型转换。

下面以Converter接口为例讲解其使用方法,假设定义了domain类User,其有一个Date 类型的成员变量birthday。

当客户端向服务端Controller发送User对象时,最常用的序列化方法就是拼接成json串,那么birthDay转换为String类型才会传到服务端。而在服务端就需要正确的转换器将String类型的birthDay转换为Date类型的。这时候我们就要编写一个Converter了

在完成Converter后就需要将其添加到Spring容器中,以备在使用时可以直接调用,我们的配置也很简单,在springmvc-config.xml中添加如下代码:

 

<!-- 装配自定义的类型转换器 --> <mvc:annotation-driven conversion-service="conversionService"/> <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <list> <bean class="com.lyh.StringToDateConverter" p:datePattern="yyyy-MM-dd"></bean> </list> </property> </bean>

 

从上面的例子可以看出,可以在这里配置多个Converter。如果使用mvc:annotation-driven/ SpringMVC会默认注册一个默认的ConversionService,即FormattingConversionServiceBean,可以满足大部分时候转换。

上面介绍了3个Converter发现都是接口,而且没有任何继承关系,这使得我很纳闷,他们3个接口没有共同的父接口如何放到一个集合中呢?于是去查看ConversionServiceFactorybean的源码:

发现其中有一个Set<?> 类型的集合,这样就可以存放多种类型的转换器了。

在完成以上配置后,就可以在Controller中使用了,但是我们不用显示的调用,Spring会帮我们完成这件事。我们只需正常使用就可以。

继续来看:

其实在前面的BeanFactoryPostProcessor也可以执行过的

如果前面没有添加,这里也可以再添加一次

开始准备实例化了,先冻结definition配置信息

来看下:getMergedLocalBeanDefinition方法

其实之前这个方法就已经调用过了,往前找

BeanDefinition 的合并

  • 1.BeanDefinition 有父子关系,有个属性叫parentName,通过parentName可以设置BeanDefinition的父子关系
  • 2.为什么要设置BeanDefinition的父子关系,因为子类可以继承父类的属性,抽出共性,跟java的继承有点像
  • 3.BeanDefinition 的合并过程就是将父子关系的 BeanDefinition 属性合并起来,如果有相同的就使用子类的
  • 什么时候做合并
  • 在初始化bean工厂的过程中调用: PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors->DefaultListableBeanFactory.getBeanNamesForType

  • DefaultListableBeanFactory.getBeanNamesForType

下面继续看FactoryBean接口

测试代码1:

先来看下

先从一级缓存获取

一级缓存并没有

调用getBean方法了

再从一级缓存中获取一次

发现还是没有

进入createBean方法

进入doCreateBean方法

进入方法createBeanInstance

进入:instantiateBean

进入instantiate方法

实例化对象

返回包装对象

添加到缓存

添加到一级缓存

返回对象

继续分析:来分析一下处理过程,先执行到这一步,可以看到一级缓存已经有MyFactoryBean对象了

继续往下执行:

这一步很关键:

根据A.class获取到了myFactoryBean对象的全限定名

同时存入缓存,key=A.class,value=myFactoryBean对象的全限定名

继续根据获取到的全限定类名获取A对象

先从缓存中获取

缓存中没有,继续往下获取

再从缓存中获取一次,还是没有,继续往下获取

进入到真正获取方法

调用getObject方法了

最后放入缓存

最后返回创建的对象

可以看到缓存起来了factoryBeanObjectCache,并没有放在一级缓存

继续看

根据类名MyFactoryBean得到了&myFactoryBean字符串

根据&myFactoryBean获取对象

从缓存中获取即可。

直接返回对象

最后总结一下

还没有分析完,下期继续

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值