一、前言
在前面的几节中我们已经介绍完refresh()的其他方法了,接下来就是finishBeanFactoryInitialization方法,初始化所有剩余的单实例Bean(没有使用懒加载的Bean).整个Spring IOC的核心,接下来我们看看这个方法到底做了哪些事情?
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 1. 初始化此上下文的转换服务,用来自定义将Spring中的某个Bean的属性从一个类型转换到另外一个类型.
// 判断Bean工厂中是否存在名称为conversionService的转换服务bean,如果存在而且类型为ConversionService,则获取该Bean实例,并将其设置到BeanFactory中
/**
* 例如:
* (1)有如下的javaBean:
* public class Person {
* public String name;
* public Date birthday;
* ...
* }
* (2)有如下的xml配置:
* <bean name="person" class="com.wb.test.Person">
* <property name="name" value="wangbing"/>
* <property name="birthday" value="1999-03-03"/>
* </bean>
* (3)有如下的测试类:
* ApplicationContext acx = new ClasspathXmlApplicationContext("test.xml");
* Person person = (Person) acx.getBean("person");
* System.out.println(person.name);
* System.out.println(person.birthday); // 改行会报错,提示字符串类型不能转换为日期类型
*
* (4)可以通过定义如下名称的bean,将某种类型的属性值转换为另外一种类型.
* <bean name="conversionService" class="com.wb.test.MyConversionService" />
* public class MyConversionService implements ConversionService {
* // 实现是否能转换以及具体转换的方法。
* public boolean canConvert(Class<?> sourceType, Class<?> targetType) {}
* public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {}
* public <T> T convert(Object source, Class<T> targetType) {}
* // 可以在该方法中实现转换逻辑。如果源类型sourceType是String类型的话,将其转换为Date类型返回。
* public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {}
* }
*/
// 2.在Spring中,如果需要配置自定义的转换器,还可以直接利用Spring提供的ConversionServiceFactoryBean来完成。自己只需要实现具体的转换逻辑即可
/**
* (1)配置conversionService对应的工厂Bean:
* <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
* <property name="converters">
* <bean class="com.wb.test.MyConverter"/>
* </property>
* </bean>
* (2)然后自己去实现MyConverter即可:
* public class MyConverter implements Converter<String,Date> {
* @Override
* public Date convert(String source) {
* DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
* try {
* return format.parse((String) source);
* } catch (ParseException e) {
* e.printStackTrace();
* }
* return null;
* }
* }
*/
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));
}
/**
* 如果beanFactory之前没有注册嵌入值解析器,则注册默认的嵌入值解析器,
* 主要用于注解属性值的解析例如:@Value("${app.name}")。
*/
// 值解析器设置的地方:在调用invokeBeanfactoryPostProcessor方法的时候,通过PropertySourcesPlaceholderConfigurer的后置处理方法设置进去的
if (!beanFactory.hasEmbeddedValueResolver()) {
// 调用resolvePlaceholders方法解析strVal对应的值
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
/**
* 初始化所有实现了LoadTimeWeaverAware接口的子类,用于类在加载进入jvm之前,动态增强类
* 这特别适用于Spring的JPA支持,其中load-time weaving加载织入对JPA类转换非常必要
*/
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// 停止使用临时的类加载器.
beanFactory.setTempClassLoader(null);
// 缓存(冻结)所有的BeanName(注册的bean定义不会被修改或进一步做处理了,因为下面马上要创建Bean的实例对象了)
beanFactory.freezeConfiguration();
// 初始化所有的单实例Bean,包括创建单实例bean的全部过程
beanFactory.preInstantiateSingletons();
}
第一步我们首先是判断此上下文是否存在转换服务,用来自定义将Spring中的某个Bean的属性从一个类型转换到另外一个类型,判断Bean工厂中是否存在名称为conversionService的转换服务bean,如果存在而且类型为ConversionService,则获取该Bean实例,并将其设置到BeanFactory中。我们来看下对应conversionService对应的实现子类:DefaultConversionService。
public class DefaultConversionService extends GenericConversionService {
/** 【懒汉式单例设计模式DCL】使用volatile禁止指令重排序 */
@Nullable
private static volatile DefaultConversionService sharedInstance;
/**
* Create a new {@code DefaultConversionService} with the set of
* {@linkplain DefaultConversionService#addDefaultConverters(ConverterRegistry) default converters}.
*/
public DefaultConversionService() {
addDefaultConverters(this);
}
/**
* Return a shared default {@code ConversionService} instance,
* lazily building it once needed.
* <p><b>NOTE:</b> We highly recommend constructing individual
* {@code ConversionService} instances for customization purposes.
* This accessor is only meant as a fallback for code paths which
* need simple type coercion but cannot access a longer-lived
* {@code ConversionService} instance any other way.
* @return the shared {@code ConversionService} instance (never {@code null})
* @since 4.3.5
*/
public static ConversionService getSharedInstance() {
DefaultConversionService cs = sharedInstance;
if (cs == null) {
synchronized (DefaultConversionService.class) {
cs = sharedInstance;
if (cs == null) {
cs = new DefaultConversionService();
sharedInstance = cs;
}
}
}
return cs;
}
/**
* Add converters appropriate for most environments.
* @param converterRegistry the registry of converters to add to
* (must also be castable to ConversionService, e.g. being a {@link ConfigurableConversionService})
* @throws ClassCastException if the given ConverterRegistry could not be cast to a ConversionService
*/
public static void addDefaultConverters(ConverterRegistry converterRegistry) {
addScalarConverters(converterRegistry);
addCollectionConverters(converterRegistry);
converterRegistry.addConverter(new ByteBufferConverter((ConversionService) converterRegistry));
converterRegistry.addConverter(new StringToTimeZoneConverter());
converterRegistry.addConverter(new ZoneIdToTimeZoneConverter());
converterRegistry.addConverter(new ZonedDateTimeToCalendarConverter());
converterRegistry.addConverter(new ObjectToObjectConverter());
converterRegistry.addConverter(new IdToEntityConverter((ConversionService) converterRegistry));
converterRegistry.addConverter(new FallbackObjectToStringConverter());
converterRegistry.addConverter(new ObjectToOptionalConverter((ConversionService) converterRegistry));
}
/**
* Add common collection converters.
* @param converterRegistry the registry of converters to add to
* (must also be castable to ConversionService, e.g. being a {@link ConfigurableConversionService})
* @throws ClassCastException if the given ConverterRegistry could not be cast to a ConversionService
* @since 4.2.3
*/
public static void addCollectionConverters(ConverterRegistry converterRegistry) {
ConversionService conversionService = (ConversionService) converterRegistry;
converterRegistry.addConverter(new ArrayToCollectionConverter(conversionService));
converterRegistry.addConverter(new CollectionToArrayConverter(conversionService));
converterRegistry.addConverter(new ArrayToArrayConverter(conversionService));
converterRegistry.addConverter(new CollectionToCollectionConverter(conversionService));
converterRegistry.addConverter(new MapToMapConverter(conversionService));
converterRegistry.addConverter(new ArrayToStringConverter(conversionService));
converterRegistry.addConverter(new StringToArrayConverter(conversionService));
converterRegistry.addConverter(new ArrayToObjectConverter(conversionService));
converterRegistry.addConverter(new ObjectToArrayConverter(conversionService));
converterRegistry.addConverter(new CollectionToStringConverter(conversionService));
converterRegistry.addConverter(new StringToCollectionConverter(conversionService));
converterRegistry.addConverter(new CollectionToObjectConverter(conversionService));
converterRegistry.addConverter(new ObjectToCollectionConverter(conversionService));
converterRegistry.addConverter(new StreamConverter(conversionService));
}
private static void addScalarConverters(ConverterRegistry converterRegistry) {
converterRegistry.addConverterFactory(new NumberToNumberConverterFactory());
converterRegistry.addConverterFactory(new StringToNumberConverterFactory());
converterRegistry.addConverter(Number.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverter(new StringToCharacterConverter());
converterRegistry.addConverter(Character.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverter(new NumberToCharacterConverter());
converterRegistry.addConverterFactory(new CharacterToNumberFactory());
converterRegistry.addConverter(new StringToBooleanConverter());
converterRegistry.addConverter(Boolean.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverterFactory(new StringToEnumConverterFactory());
converterRegistry.addConverter(new EnumToStringConverter((ConversionService) converterRegistry));
converterRegistry.addConverterFactory(new IntegerToEnumConverterFactory());
converterRegistry.addConverter(new EnumToIntegerConverter((ConversionService) converterRegistry));
converterRegistry.addConverter(new StringToLocaleConverter());
converterRegistry.addConverter(Locale.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverter(new StringToCharsetConverter());
converterRegistry.addConverter(Charset.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverter(new StringToCurrencyConverter());
converterRegistry.addConverter(Currency.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverter(new StringToPropertiesConverter());
converterRegistry.addConverter(new PropertiesToStringConverter());
converterRegistry.addConverter(new StringToUUIDConverter());
converterRegistry.addConverter(UUID.class, String.class, new ObjectToStringConverter());
}
}
我们可以看得到,这个DefaultConversionService里面主要是注册了一些Converter和一些ConverterFactory。当需要集中整个类层次结构的转换逻辑时(例如,从转换String为Enum对象时),可以实现 ConverterFactory。需要复杂的Converter实现时,请考虑使该 GenericConverter接口。使用更灵活但不太强类型的签名Converter,GenericConverter支持在多个源类型和目标类型之间进行转换。此外,GenericConverter还可以在实现转换逻辑时使用可用的源和目标字段上下文。
以上还是一些赋值的操作,真正进行实例化的还是在:preInstantiateSingletons,我們來看下他具体的源码:
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// 创建BeanDefinitionNames的副本BeanNames用于后续的遍历,以允许init等方法注册新的bean定义.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// 遍历所有的beanNames,触发所有非懒加载单例bean的初始化,即:创建所有的单实例Bean
for (String beanName : beanNames) {
// 获取beanName对应的MergedBeanDefinition.在实例化之前将所有的beanDefiniton对象在转换成RootBeanDefinition,进行缓存,后续在需要马上实例化的时候直接获取定义信息,而定义信息中
// 如果包含了父类就需要先实例化父类。
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 如果bd对应的Bean实例满足:(不是抽象类 && 是单例 && 不是懒加载)
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 判断BeanName对应的Bean实例是否是FactoryBean.
/**
* BeanFactory 与FactoryBean的区别
* 相同点:都是用来创建bean对象的
* 不同点:
* 如果使用了BeanFactory那么就必须要严格遵循SpringBean的生命周期接口,例如从实例化 ——>初始化等等一系列方法,此流程非常的负责且麻烦
* 如果使用FactotyBean则创建bean就更加方便简单,不需要遵循spring的生命周期流程,
* 他主要有getObject():直接返回一个对象,isSingleton():判断是否是单例,getObjectTye():返回需要返回对象的类型三个方法。
*/
if (isFactoryBean(beanName)) {
// 通过beanName获取FactoryBean的实例,factoryBean的名称是:"&" + beanName
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
// 判断这个FactoryBean是否需要紧急初始化.
// System.getSecurityManager()方法是获取系统权限管理器,Java为了防止恶意代码执行(修改,删除操作系统文件),做了权限管理,
// 默认的安全管理器配置文件是: $JAVA_HOME/jre/lib/security/java.policy
/**
* 在做访问控制决定时,如果遇到通过调用不带上下文参数(请参阅下文,以获取关于上下文参数的信息)的 doPrivileged 标记为“特权”的调用方,
* 则 checkPermission 方法将停止检查。如果该调用方的域具有指定的权限,则不进行进一步检查,并且 checkPermission 正常返回,
* 指示允许所请求的访问。如果该域不具有指定的权限,则通常抛出异常。
*
*
* AccessController.doPrivileged()方法的例子:
* 假设有这样一种情况:A程序想在 C:\\Users\\Jack\\Desktop\\test1 这个目录中新建一个文件,但是它没有相应的权限,
* 但是它引用了另外一个Jar包B,刚好B有权限在C:\\Users\\Jack\\Desktop\\test1目录中新建文件,
* 还有更巧的是B在新建文件的时候采用的是AccessController.doPrivileged方法进行的,这种情况下,A就可以调用B的创建文件的方法进行创建文件了。
*/
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) {
// 如果需要紧急初始化,则通过beanName获取Bean的实例.
getBean(beanName);
}
}
}
else {
// 如果BeanName对应的Bean实例不是FactoryBean,则通过BeanName去获取Bean实例.
getBean(beanName);
}
}
}
/**
* 上一步for循环中已经创建完了所有的单实例Bean,这个for循环中,会拿出所有的单实例Bean,
* 然后遍历,判断单实例bean是否实现了SmartInitializingSingleton接口,如果实现了该接口,
* 则调用单实例Bean的afterSingletonsInstantiated方法
*/
for (String beanName : beanNames) {
// 获取beanName对应的bean实例
Object singletonInstance = getSingleton(beanName);
// 判断当前的bean是否实现了SmartInitializingSingleton接口.
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
// 触发SmartInitializingSingleton实现类的afterSingletonInstantiated方法.
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
/**
* 如果实现了SmartInitializingSingleton接口,则会调用afterSingletonInstantiated方法
* 例如@EventListener注解的实现原理,就是利用EventListenerMethodProcessor后置处理器完成的,
* 而在EventListenerMethodProcessor中就是实现了SmartInitializingSingleton接口
*/
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
在之后的内容你可能会频繁的见到 “MergedBeanDefinition” 这个词,因此这边先稍微讲解一下,有助于你更好的理解。 MergedBeanDefinition:这个词其实不是一个官方词,但是很接近,该词主要是用来表示 “合并的 bean 定义”,因为每次都写 “合并的 bean 定义” 有点太绕口, 因此我在之后的注释或解析中或统一使用 MergedBeanDefinition 来表示 “合并的 bean 定义”。 之所以称之为 “合并的”,是因为存在 “子定义” 和 “父定义” 的情况。对于一个 bean 定义来说,可能存在以下几种情况: (1)该 BeanDefinition 存在 “父定义”:首先使用 “父定义” 的参数构建一个 RootBeanDefinition,然后再使用该 BeanDefinition 的参数来进行覆盖。 (2)该 BeanDefinition 不存在 “父定义”,并且该 BeanDefinition 的类型是 RootBeanDefinition:直接返回该 RootBeanDefinition 的一个克隆。 (3)该 BeanDefinition 不存在 “父定义”,但是该 BeanDefinition 的类型不是 RootBeanDefinition:使用该 BeanDefinition 的参数构建一个 RootBeanDefinition。 之所以区分出2和3,是因为通常 BeanDefinition 在之前加载到 BeanFactory 中的时候,通常是被封装成 GenericBeanDefinition 或 ScannedGenericBeanDefinition, 但是从这边之后 bean 的后续流程处理都是针对 RootBeanDefinition,因此在这边会统一将 BeanDefinition 转换成 RootBeanDefinition。 在我们日常使用的过程中,通常会是上面的第3种情况。如果我们使用 XML 配置来注册 bean,则该 bean 定义会被封装成:GenericBeanDefinition; 如果我们使用注解的方式来注册 bean,也就是 + @Compoment,则该 bean 定义会被封装成 ScannedGenericBeanDefinition。
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// Quick check on the concurrent map first, with minimal locking.
// 检查beanName对应的MergedBeanDefinition是否存在于缓存中.
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null) {
// 如果存在于缓存中,则直接返回.
return mbd;
}
// 如果不再缓存中
// 先调用getBeanDefinition()方法根据beanName获取对应的BeanDefinition,从beanDefinitionMap缓存中获取,获取不到直接抛异常.
// 然后调用getMergedBeanDefinition(beanName, getBeanDefinition(beanName))方法根据beanName和对应的beanDefinition获取mergedBeanDefinition.
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
throws BeanDefinitionStoreException {
return getMergedBeanDefinition(beanName, bd, null);
}
protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
throws BeanDefinitionStoreException {
// 加同步锁,然后进行操作.
synchronized (this.mergedBeanDefinitions) {
// 用于存放返回结果.
RootBeanDefinition mbd = null;
// Check with full lock now in order to enforce the same merged instance.
if (containingBd == null) {
// 检查beanName对应的MergedBeanDefinition是否存在于缓存中.
mbd = this.mergedBeanDefinitions.get(beanName);
}
// 如果beanName对应的BeanDefinition不在缓存中时
if (mbd == null) {
if (bd.getParentName() == null) {
// 如果bd的parentName为空,表示bd没有父定义,不需要与父定义进行合并操作.即:bd的MergedBeanDefinition就是bd自己
// Use copy of given root bean definition.
if (bd instanceof RootBeanDefinition) {
// 如果bd的类型为RootBeanDefinition,则bd的MergedBeanDefinition就是bd自己,直接克隆一个副本
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
}
else {
// 否则使用bd构建一个RootBeanDefinition.
// 一般情况下,BeanDefinition在被加载之后是GenericBeanDefinition(xml) 或者 ScannedGenericBeanDefinition(注解)
mbd = new RootBeanDefinition(bd);
}
}
else {
// Child bean definition: needs to be merged with parent.
// 否则,bd存在着父定义,需要和父定义合并.
BeanDefinition pbd;
try {
// 获取父定义的BeanName.
String parentBeanName = transformedBeanName(bd.getParentName());
// 如果父定义的beanName和当前bean的beanName不同
if (!beanName.equals(parentBeanName)) {
// 则获取父定义的MergedBeanDefinition(也就是bd的爷爷定义...)
/**
* 一般情况下,Spring 通过反射机制利用 bean 的 class 属性指定实现类来实例化 bean。
* 而 FactoryBean 是一种特殊的 bean,它是个工厂 bean,可以自己创建 bean 实例,如果一个类实现了 FactoryBean 接口,
* 则该类可以自己定义创建实例对象的方法,只需要实现它的 getObject() 方法。
*
* 很多中间件都利用 FactoryBean 来进行扩展。例如:
*
* public class AppleFactoryBean implements FactoryBean<Apple> {
@Override
public Apple getObject() throws Exception {
Apple apple = new Apple();
apple.setName("bigApple");
return apple;
}
@Override
public Class<?> getObjectType() {
return Apple.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
注意:
为了区分 “FactoryBean” 和 “FactoryBean 创建的 bean 实例”,Spring 使用了 “&” 前缀。假设我们的 beanName 为 apple,
则 getBean("apple") 获得的是 AppleFactoryBean 通过 getObject() 方法创建的 bean 实例;
而 getBean("&apple") 获得的是 AppleFactoryBean 本身。
*
*/
pbd = getMergedBeanDefinition(parentBeanName);
}
else {
// 如果父定义的beanName和bd的beanName相同,则拿到父亲的BeanFactory
// 只有存在父BeanFactory的情况下,才允许父定义beanName与自己相同,否则就是将自己设置为父定义.
BeanFactory parent = getParentBeanFactory();
// 如果父BeanFactory是ConfigurableBeanFactory,则通过BeanFactory获取父定义的MergedBeanDefinition.
if (parent instanceof ConfigurableBeanFactory) {
pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
}
else {
// 否则抛出异常.
throw new NoSuchBeanDefinitionException(parentBeanName,
"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
"': cannot be resolved without an AbstractBeanFactory parent");
}
}
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
}
// Deep copy with overridden values.
// 使用父定义pbd构建一个新的RootBeanDefinition对象(通过深拷贝)
mbd = new RootBeanDefinition(pbd);
// 然后使用bd覆盖父定义.
mbd.overrideFrom(bd);
}
// Set default singleton scope, if not configured before.
// 如果没有设置Scope属性,默认设置为singleton.
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
}
// A bean contained in a non-singleton bean cannot be a singleton itself.
// Let's correct this on the fly here, since this might be the result of
// parent-child merging for the outer bean, in which case the original inner bean
// definition will not have inherited the merged outer bean's singleton status.
// 如果containingBd不为空 && 不是单实例的 && mbd为单实例,则将mbd的scope属性设置为containingBd的scope属性.
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
mbd.setScope(containingBd.getScope());
}
// Cache the merged bean definition for the time being
// (it might still get re-merged later on in order to pick up metadata changes)
// 如果containingBd为空,而且设置了缓存Bean的元数据,则将beanName和mbd放入到beanDefinition的缓存中,便于以后可以直接取出使用.
if (containingBd == null && isCacheBeanMetadata()) {
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
return mbd;
}
}
好了,这一节我们先讲到这里,这里大家应该而已晓得怎么自定义一个converter,跟了解getMergedLocalBeanDefinition做了哪些事情,大家可以看到,在实例化之前这里会先去判断是不是FactoryBean。
我们可以思考一个问题,FactoryBean跟BeanFactory有哪些区别,Spring是如何去管理FactoryBean的?