前言
本系列是对tiny-spring项目的详细解读,聚焦spring-beans
的基本实现,对应着(first~sixth)-stage
这六个构建过程。
上一篇介绍了Spring对资源的抽象、读取和解析,可以说是完成了一系列准备工作,剩下的就是等着BeanFactory
出场,从准备好的BeanDefinition
中提取信息生成对象完成依赖注入了。
引入BeanFactory
BeanFactory
接口仅仅定义了基本的查询和获取功能,更多高级的功能都定义在其子接口中,实际的BeanFactory
实现类会实现这些子接口,从而获得非常完备的功能。这样设计的好处是每个接口都专注于一部分功能,最小化了接口的职责,只有在确实需要时才转型成更合适的接口,毕竟大多是时候BeanFactory.getBean(...)
就满足需求了,不是吗?上一篇也提到过,BeanFactory
的实现类同时也会实现BeanDefinitionRegistry
接口,进而持有beanName -> BeanDefinition
的关联关系,BeanFactory
接口定义的查询和获取功能便是基于此而展开的。
Spring本身也是面向接口的,而且它的接口分得都很细,源码中很多类不仅要继承自一个抽象基类还要实现2~3个接口,这些抽象类和接口很多也有继承关系,看源码的话确实会比较累。闲话少提,下面看看BeanFactory
的定义:
// 输入命令git checkout fourth-stage,切换到第四阶段,可以看到BeanFactory家族的基本框架
/**
* BeanFactory持有从xml解析出来的
* BeanDefinition,根据BeanDefinition
* 提供的信息去做JavaBean的创建、管理工作。
*
* 这个接口只提供了最小的功能集,恰恰也是一般客
* 户端程序用得最多的部分。更多高级功能都定义在
* 其子接口中,比如ListableBeanFactory、ApplicationContext。
*/
public interface BeanFactory {
/**
* 通过beanName返回BeanFactory管理的一个对象。
*/
@NotNull
Object getBean(@NotNull String beanName) throws BeansException;
/**
* 通过beanName返回BeanFactory管理的一个对象,附加类型检查。
*/
@NotNull
<T> T getBean(@NotNull String beanName, @Nullable Class<T> requiredType) throws BeansException;
/**
* BeanFactory中是否存在名称为beanName的对象。
* 该算法会查看BeanFactory持有的BeanDefinition来
* 判断,因此不一定会导致对象的实例化。
*/
boolean containsBean(@NotNull String beanName);
/**
* 名称为beanName的对象类型是singleton还是prototype。
* 同样会查看持有的BeanDefinition,也因此不一定会导致
* 对象的实例化。
*/
boolean isSingleton(@NotNull String beanName) throws BeansException;
}
简单介绍一下BeanFactory
的几个子接口:
ListableBeanFactory
:添加了查询和访问多个BeanDefinition
的能力,BeanFactory
只针对单个BeanDefinition
进行操作ConfigurableBeanFactory
:添加了配置BeanFactory
的能力,比如可以注册自定义的PropertyEditor
来执行类型转换,也可以添加BeanPostProcessor
从而进入bean的生命周期,还可以直接向BeanFactory
中注册单实例的bean而不通过BeanDefinition
(多用于框架内部注册后置处理器)ConfigurableListableBeanFactory
:组合了ListableBeanFactory
和ConfigurableBeanFactory
接口的功能,并添加了提前初始化所有非懒加载的bean的功能AutowireCapableBeanFactory
:添加了自动装配容器中bean的能力
关于PropertyEditor
看过上一篇我们知道不管是setter注入还是构造函数注入,xml配置文件能够表示的可被注入的类型有<list>
、<ref>
和<value>
(<null>
的话没有转换的必要就不讨论了)这三种。其中<list>
转成数组或java.util.List
、ref
转换成容器中的其他bean是非常固定的,只有<value>
取出来的是字符串,而对应的bean属性可能是float
、double
或Date
等其它类型,这一层类型转换Spring就是使用PropertyEditor
来做的。NOTE: 类型转换在Spring中是一个比较复杂的部分,写到BeanFactory.getBean(...)
的实现时我们再说。
现在让我们来看看要如何实现一个PropertyEditor
。简而言之,实现一个PropertyEditor
有一个相当固定的流程,比如要实现一个String
转Date
的PropertyEditor
:
- 创建一个类继承自
PropertyEditorSupport
重写
setAsText(String text)
- 将形参
text
转成Date
类型的数据 - 调用
setValue(...)
保存上一步转好的Date
类型数据
- 将形参
- (可选)重写
String getAsText()
将转换好的Date
转回String
public class DatePropertyEditor extends PropertyEditorSupport {
// 日期和时间格式
private String datePattern;
public String getDatePattern() {
return datePattern;
}
public void setDatePattern(String datePattern) {
this.datePattern = datePattern;
}
@Override
public void setAsText(String text) throws IllegalArgumentException {
try {
// 1. 将String转成Date
SimpleDateFormat format = new SimpleDateFormat(getDatePattern());
Date date = format.parse(text);
// 2. 调用setValue进行保存
setValue(date);
} catch (ParseException e) {
throw new IllegalArgumentException("转换失败", e);
}
}
@Override
public String getAsText() {
// 1. 获取保存的Date
Date date = (Date) getValue();
// 2. 转回String
return new SimpleDateFormat(getDatePattern()).format(date);
}
}
关于AbstractBeanFactory
规划好BeanFactory
的基本框架后,就需要有具体的类去实现它。Spring提供的AbstractBeanFactory
就是这样一个模板类,它实现了ConfigurableBeanFactory
接口。通过上一篇我们知道,bean可以配置成singleton
或是prototype
两种类型,对单实例的bean,实现上Spring通过缓存来避免二次创建(这也是Spring的单例模式和GoF单例模式的区别,Spring的单例是相对于BeanFactory
来说的),而ConfigurableBeanFactory
有直接注册单实例bean的能力(实现上就是直接往缓存里写数据),这算是AbstractBeanFactory
选择实现ConfigurableBeanFactory
的一个原因吧,可以避免暴露缓存。而ListableBeanFactory
接口呢?它可以操作多个BeanDefinition
,而BeanDefinition
是由BeanDefinitionRegistry
持有和管理的,因此不适合一开始就实现这个接口,应该和BeanDefinitionRegistry
放在一起实现。我们来看一下getBean(...)
的实现逻辑:
@Override
public Object getBean(String beanName) throws BeansException {
// 处理一下是FactoryBean的情况
String resolvedBeanName = getResolvedBeanName(beanName);
// 查一下缓存,看看是否已经创建了
Object bean = singletonMap.get(resolvedBeanName);
// 缓存命中
if (bean != null) {
// 可能是FactoryBean,根据请求的是
// FactoryBean本身还是其生产的对象,要分别处理
return getBeanFromSharedInstance(beanName, bean);
}
// 缓存未命中,此时就要通过BeanDefinition中保存的相关信息去创建bean了
// 在我们的实现中不支持父子bean工厂,因此没有额外的BeanDefinition
// 合并操作,实现起来要简单很多。
BeanDefinition mbd = getBeanDefinition(resolvedBeanName);
if (mbd != null) {
if (mbd.isSingleton()) {
// "先检查后执行"这类操作基本上都不是线程安全的
// Collection.synchronizedMap是以自身作为锁,这里也用同一把锁来保护
synchronized (singletonMap) {
// getBean()方法并没有被整个同步住,因此这里再检查一下
bean = singletonMap.get(resolvedBeanName);
// 确实没有才创建
if (bean == null) {
System.out.println("正在创建singleton bean[" + resolvedBeanName + "]");
bean = createBean(resolvedBeanName, mbd);
// 加入缓存
addSingleton(resolvedBeanName, bean);
}
}
// 这个bean可能是FactoryBean
return getBeanFromSharedInstance(beanName, bean);
} else {
System.out.println("正在创建prototype bean[" + beanName + "]");
return createBean(beanName, mbd);
}
}
return null;
}
这里有必要提一下FactoryBean
,这是Spring支持的一种特殊的bean——它本身是一个factory。对FactoryBean
来说,它只能被配置成单例的,因为我们关心的是它生产的对象。如果一个bean是FactoryBean
,那么根据beanName
获取的是它生产的对象,想要获取FactoryBean
本身,需要在beanName
前添加&
前缀。
/**
* bean自身是一个factory.
* 如果一个bean实现了这个接口,那么它会被当做工厂使用,而不再是普通的bean。
*/
public interface FactoryBean {
/**
* 此前缀用于区分是查询FactoryBean本身还是其创建的对象
*/
String FACTORY_BEAN_PREFIX = "&";
/**
* 返回一个此工厂管理的对象,和BeanFactory一样,也支持singleton pattern和
* prototype pattern。
*/
Object getObject() throws Exception;
/**
* 返回此FactoryBean创建的对象的类型。
*/
Class getObjectType();
/**
* 这个FactoryBean管理的bean是singleton还是prototype?
* FactoryBean本身的scope由BeanFactory管理。
*
* 如果返回true,也必须保证getObject()永远返回同一对象。
*/
boolean isSingleton();
}
可以看到,getBean(...)
逻辑非常清晰:首先查看singleton缓存,若命中,处理一下FactoryBean
的情况并返回缓存的对象,若未命中,此时就要根据beanName -> BeanDefinition
的关联关系找到对应的BeanDefinition
,根据BeanDefinition
描述的信息去创建对象了。前面提到过AbstractBeanFactory
不是一个BeanDefinitionRegistry
,因而真正的创建过程就需要留给子类去实现了,至此第一个模板方法createBean(...)
就诞生了,这种模式也被成为模板方法模式
。我们继续往下看:
@Override
public boolean containsBean(String beanName) {
String resolvedBeanName = getResolvedBeanName(beanName);
// 先看看缓存是否命中
if (singletonMap.containsKey(resolvedBeanName)) {
return true;
}
// 再查询一下是否有对应的BeanDefinition
// return getBeanDefinition(resolvedBeanName) != null;
return containsBeanDefinition(resolvedBeanName);
}
@Override
public boolean isSingleton(String beanName) throws BeansException {
String resolvedBeanName = getResolvedBeanName(beanName);
// 先看看缓存是否命中
if (singletonMap.containsKey(resolvedBeanName)) {
return true;
}
// 再查询一下对应的BeanDefinition
// 这里没有去考虑是FactoryBean的情况
BeanDefinition mbd = getBeanDefinition(resolvedBeanName);
if (mbd != null) {
return mbd.isSingleton();
}
return false;
}
containsBean(String beanName)
的逻辑相对简单:若缓存命中的话当然包含,否则只需要查询一下此beanName
有没有对应的BeanDefinition
即可。在我们的实现中其实判断一下getBeanDefinition(resolvedBeanName) != null
也是可以的,不过再提供一个模板方法containsBeanDefinition(...)
留给子类去实现也是一个不错的选择。
isSingleton(...)
呢?若缓存命中当然是了,否则就需要获取一下此beanName
对应的BeanDefinition
,看看定义的是不是单例。这里没有去处理FactoryBean
的情况,如果是FactoryBean
的话,就需要先把FactoryBean
本身创建出来(通过getBean(...)
),再去查询FactoryBean.isSingleton()
。我们知道FactoryBean
本身肯定是单例的,查询它没有太大意义,我们更关心的是它生产的对象。
看完了bean的获取,现在让我们看一看singleton bean的销毁:
@Override
public void destroySingletons() {
synchronized (singletonMap) {
Set<String> keySet = singletonMap.keySet();
for (String key : keySet) {
destroySingleton(key, singletonMap.get(key));
}
singletonMap.clear();
}
}
遍历singleton缓存,逐个销毁,逻辑上没什么好说的,只是这里又引入了一个模板方法destroySingleton(...)
。我们知道,Spring对bean的生命周期是有一个统一管理的,singleton bean在被销毁时,会调用自定义的detroy-method
,会执行DisposableBean
回调,不过连createBean(...)
都需要子类实现,destroySingleton(...)
当然也只有子类知道要怎么做了。讲到这里,AbstractBeanFactory
的主要内容也就讲完了。
关于AbstractAutowireCapableBeanFactory
AbstractAutowireCapableBeanFactory
继承自AbstractBeanFactory
并实现了AutowireCapableBeanFactory
接口,和AbstractBeanFactory
一样,它也没有实现BeanDefinitionRegistry
接口,因此涉及对BeanDefinition
的查询也需要交给子类去实现,但它实现了来自AbstractBeanFactory
的createBean(...)
模板方法,并在这个过程中加入了自动装配的功能,我们来看一下具体实现:
// 输入命令git checkout sixth-stage,切换到第六阶段,可以看到createBean(...)的实现
@Override
public Object createBean(String beanName, BeanDefinition mbd) {
// 确保依赖的bean先得到初始化
String[] dependsOnBeanNames = mbd.getDependsOn();
if (dependsOnBeanNames != null) {
for (String dependsOnBeanName : dependsOnBeanNames) {
getBean(dependsOnBeanName);
}
}
BeanWrapper beanWrapper = null;
// 是构造函数注入或持有构造函数的参数
if (mbd.getResolvedAutowireMode() == BeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues()) {
beanWrapper = autowireConstructor(beanName, mbd);
} else {
// 不是的话就走普通的解析赋值路线
beanWrapper = new BeanWrapper(mbd.getBeanClass());
registerPropertyEditors(beanWrapper);
}
Object bean = beanWrapper.getWrappedInstance();
// 提前缓存单实例bean
// 只要保证都是先创建后赋值,就可以解决循环依赖
if (mbd.isSingleton()) {
addSingleton(beanName, bean);
}
// 给属性赋值
populateBean(beanName, mbd, beanWrapper);
// 生命周期回调
try {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(this);
}
bean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
invokeInitMethods(bean, mbd);
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
} catch (Exception e) {
throw new BeansException("调用生命周期函数失败", e);
}
return bean;
}
它的逻辑是这样的:首先保证依赖的bean得到初始化,方法是遍历depends-on
属性指定的beanName(s)
并调用getBean(...)
,然后才轮到自身的初始化;接下来通过BeanDefinition
查看一下是否指定了装配模式为AUTOWIRE_CONSTRUCTOR
或者有提供构造函数注入的相关信息,满足其一就走构造函数装配,否则的话就通过无参构造器实例化对象。以上不管哪种,都会创建一个新的对象,之后只要装配好setter注入的相关属性(通过populateBean(...)
),最后统一执行生命周期回调,整个创建过程就宣告结束。
这里有两个值得注意的地方,第一个是提前缓存singleton bean,为什么要这么做呢?答案是为了解决bean之间的循环引用。只要遵循先创建再缓存后注入
的步骤就可以绕开bean之间的循环引用,这样做了就不会出现注入时因为找不到相关bean从而反复创建直至stack over flow
,这也正是createBean(...)
的做法。仔细想想是不是这么回事?
第二个是引入了BeanWrapper
,它的出现使得与依赖注入和类型转换相关的代码被提取了出来,进入到BeanWrapper
而不是留在AbstractAutowireCapableBeanFactory
中,可以看到BeanWrapper
包装的正是新创建的对象,这也是它名称的由来。
关于BeanWrapper
围绕BeanWrapper
的是关于依赖注入和类型转换两大块内容,因而有必要好好聊一下BeanWrapper
。
前面提到,BeanWrapper
包装了新创建的对象,依赖注入最终也是要作用到被包装对象上,因而BeanWrapper
的get/set
最终也需要反映到被包装对象的get/set
,这部分抽象出来就是PropertyAccessor
,真实的Spring是支持级联属性设置的,我们这里就不做支持了。
/**
* 定义了访问JavaBean getter/setter 的方式,不支持级联属性。
*/
public interface PropertyAccessor {
/**
* 给bean的propertyName属性设置值propertyValue,相当于bean.setPropertyName(propertyValue)
*/
void setPropertyValue(String propertyName, Object propertyValue) throws BeansException;
/**
* 获取bean的名为propertyName的属性的值,相当于bean.getPropertyName()
*/
Object getPropertyValue(String propertyName) throws BeansException;
/**
* 获取特定属性的描述信息,我们关心属性对应的setter和getter是否存在,是否可访问等
*/
PropertyDescriptor getPropertyDescriptor(String propertyName) throws BeansException;
/**
* 获取所有属性的描述信息
*/
PropertyDescriptor[] getPropertyDescriptors() throws BeansException;
}
再说类型转换,它的作用是将一个对象转换成另一种类型的对象(这不是废话嘛zzz),因为我们从xml配置中获取到的类型并不一定是bean属性的最终类型。这一层的抽象是TypeConverter
,TypeConverter
的定义也很简单:
/**
* 将PropertyValue.value转换成实际的类型,
* 这个接口是使用PropertyEditor进行转换。
*/
public interface TypeConverter {
/**
* 将value转换成requiredType类型的实例。
*/
Object convertIfNecessary(@Nullable Object value,
@NotNull Class<?> requiredType) throws BeansException;
/**
* 将value转换成descriptor.getPropertyType()类型的实例。
*/
@Nullable
Object convertIfNecessary(@Nullable Object value,
@NotNull PropertyDescriptor descriptor) throws BeansException;
}
前面有提到过类型转换是使用PropertyEditor
来进行的,而PropertyEditor
的注册是由ConfigurableBeanFactory
来管理的,这里就涉及一个PropertyEditor
的同步问题,我们需要把ConfigurableBeanFactory
管理的PropertyEditor
同步给BeanWrapper
一份,这一层抽象出来对应的是PropertyEditorRegistry
,PropertyEditorRegistrySupport
是它的默认实现,非常简单的一个类,这里就不多说了。至于PropertyEditorRegistrar
,讲到ApplicationContext
我们再说吧。
/**
* PropertyEditor注册器。
*/
public interface PropertyEditorRegistry {
/**
* 注册一个PropertyEditor,此PropertyEditor
* 处理的类型是requiredType。
*/
void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor);
/**
* 根据requiredType返回一个PropertyEditor。
*/
PropertyEditor findCustomEditor(Class<?> requiredType);
}
说到这里,本来让BeanWrapper
继承PropertyEditorRegistrySupport
再实现PropertyAccessor
就可以了,Spring在这里又故技重施,添加了一层TypeConverterSupport
,将实际的转换工作代理给了TypeConverterDelegate
。BeanWrapper
的层次结构大体上就是这样了,我们来看看它的具体实现:
@Override
public void setPropertyValue(String propertyName, Object propertyValue) throws BeansException {
PropertyDescriptor pd = getPropertyDescriptor(propertyName);
if (pd == null) {
throw new BeansException("找不到[" + propertyName + "]属性对应的PropertyDescriptor");
}
Method writeMethod = pd.getWriteMethod();
if (writeMethod == null) {
throw new BeansException("找不到[" + propertyName + "]属性对应的setter方法");
}
try {
// 获取要转换成的类型
Class<?> propertyType = pd.getPropertyType();
// 做转换
Object newValue = convertIfNecessary(propertyValue, pd);
if (propertyType.isPrimitive() &&
(newValue == null || "".equals(newValue))) {
throw new IllegalArgumentException("属性[" + propertyName + "]的类型是基本类型[" + propertyType + "]");
}
// 调用setter设置进去
writeMethod.invoke(object, newValue);
} catch (InvocationTargetException | IllegalAccessException e) {
throw new BeansException("无法调用此getter - " + writeMethod.getName());
} catch (IllegalArgumentException e) {
throw new BeansException(e);
}
}
setPropertyValue(...)
方法首先会去获取属性对应的setter
,而由PropertyDescriptor
可知属性的实际类型,通过这个信息就知道需不需要做进一步的类型转换,无论转换与否,最后都会得到一个值,再调用之前获取的setter
设置进去就完成了依赖注入。NOTE:和PropertyDescriptor
相关的内容是通过Introspector.getBeanInfo(...)
来获取的,比较简单,这里就不多说了,各位同学自行翻看一下便好。
@Override
public Object getPropertyValue(String propertyName) throws BeansException {
PropertyDescriptor pd = getPropertyDescriptor(propertyName);
if (pd == null) {
throw new BeansException("找不到[" + propertyName + "]属性对应的PropertyDescriptor");
}
Method readMethod = pd.getReadMethod();
if (readMethod == null) {
throw new BeansException("找不到[" + propertyName + "]属性对应的getter方法");
}
try {
// 调用getter来获取
return readMethod.invoke(object);
} catch (InvocationTargetException | IllegalAccessException e) {
throw new BeansException("无法调用此getter - " + readMethod.getName());
}
}
getPropertyValue(...)
同理,获取属性对应的getter
再调用。真正的重心在convertIfNecessary(...)
,由于这一层被代理给了TypeConverterDelegate
,所以我们去看看TypeConverterDelegate
是如何处理类型转换的。
关于TypeConverterDelegate
TypeConverterDelegate
是真正利用PropertyEditor
执行类型转换的地方:
/**
* 类型转换的核心算法。
*/
private Object convertIfNecessary(String propertyName, Object value, Class<?> requiredType, PropertyDescriptor descriptor) {
Object convertedValue = value;
// 查找一下这个类型有没有对应的PropertyEditor
PropertyEditor editor = propertyEditorRegistry.findCustomEditor(requiredType);
// 若没有,尝试从PropertyDescriptor生成
if (editor == null && descriptor != null) {
Class<?> editorClass = descriptor.getPropertyEditorClass();
if (editorClass != null) {
editor = (PropertyEditor) ClassUtils.instantiateClass(editorClass);
}
}
// 仍没有
if (editor == null) {
// 获取默认的PropertyEditor
editor = propertyEditorRegistry.findDefaultEditor(requiredType);
// 也没有默认的PropertyEditor
if (editor == null) {
// 查询标准JavaBean的PropertyEditor
editor = PropertyEditorManager.findEditor(requiredType);
}
}
// 若类型不匹配,执行转换
if (editor != null || (requiredType != null && !ClassUtils.isAssignableValue(requiredType, convertedValue))) {
convertedValue = doConvertValue(convertedValue, requiredType, editor);
}
if (requiredType != null) {
if (convertedValue != null) {
if (String.class.equals(requiredType) && ClassUtils.isPrimitiveOrWrapper(convertedValue.getClass())) {
// 基本类型转String
return convertedValue.toString();
} else if (requiredType.isArray()) {
// 转数组
return convertToTypedArray(convertedValue, propertyName, requiredType.getComponentType());
} else {
// handled above
}
}
if (!ClassUtils.isAssignableValue(requiredType, convertedValue)) {
throw new IllegalArgumentException("无法将name = [" + propertyName + "], value = [" + value + "]" + "的属性转换成[" + requiredType + "]类型");
}
}
return convertedValue;
}
首先根据属性的类型查询对应的PropertyEditor
,这一过程是层层递进的;如果有找到,并且需要转换,就调用doConvertValue(...)
进行转换,如果没找到,就尝试应用一些内置的类型转换规则。实际上Spring的实现非常复杂,这里已经做了大幅删减。
private Object doConvertValue(Object value, Class<?> requiredType, PropertyEditor editor) {
Object convertedValue = value;
if (editor != null) {
if (convertedValue instanceof String) {
System.out.println("正在使用[" + editor + "]将字符串转换成[" + requiredType + "]类型");
String newTextValue = (String) convertedValue;
editor.setAsText(newTextValue);
return editor.getValue();
} else {
try {
editor.setValue(convertedValue);
Object newConvertedValue = editor.getValue();
if (newConvertedValue != convertedValue) {
convertedValue = newConvertedValue;
}
} catch (Exception ex) {
System.out.println("[" + editor.getClass().getName() + "]不支持setValue方法");
}
}
}
return convertedValue;
}
doConvertValue(...)
的实现也很简单,就是直接使用PropertyEditor
进行转换。对于value
不是String
的情况(没怎么见过这种情况,有老铁说一下嘛),使用的是PropertyEditor.setValue
和PropertyEditor.getValue
,标准实现中这两方法并没有做任何实际的转换,这就需要用户注册自定义的PropertyEditor
重写这两方法执行自定义的转换了。讲到这里,整个BeanWrapper
及其相关的类和接口的关系就比较清晰了,是时候回去再谈AbstractAutowireCapableBeanFactory
了。
再谈AbstractAutowireCapableBeanFactory
前面提到,createBean(...)
调用了populateBean(...)
来执行依赖注入,兜兜转转解释完了与BeanWrapper
相关的类和接口,再来看populateBean(...)
的实现就比较容易了。
private void populateBean(String beanName, BeanDefinition mbd, BeanWrapper beanWrapper) {
// 拿到所有setter注入的相关信息
MutablePropertyValues pvs = mbd.getPropertyValues();
// 如果有自动装配,需要提取自动装配的对象来完善MutablePropertyValues
if (mbd.getResolvedAutowireMode() == BeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == BeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues mpvs = new MutablePropertyValues(pvs);
if (mbd.getResolvedAutowireMode() == BeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, beanWrapper, mpvs);
}
if (mbd.getResolvedAutowireMode() == BeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, beanWrapper, mpvs);
}
pvs = mpvs;
}
// 执行注入
applyPropertyValues(beanName, mbd, beanWrapper, pvs);
}
方法首先拿到xml中已配置的setter注入的相关信息,之后再查看一下自动装配机制的设置情况。我们知道,Spring的自动装配机制是由框架本身来推导要注入的信息,对于byName
类型,是注入配置文件中和属性同名的bean,对于byType
类型,是注入配置文件中和属性类型兼容的bean,如果有多个的话,Spring无法替用户进行选择,就会抛出异常。注意由Spring本身来进行推导的话,此时的BeanDefinition
中就会缺失这部分信息,autowireByName(...)
和autowireByType
两个方法就是用来完善BeanDefinition
缺失的信息的。
private void autowireByName(String beanName, BeanDefinition mbd,
BeanWrapper bw, MutablePropertyValues pvs) {
String[] propertyNames = unsatisfiedObjectProperties(mbd, bw);
for (String propertyName : propertyNames) {
if (containsBean(propertyName)) {
Object bean = getBean(propertyName);
pvs.addPropertyValue(new PropertyValue(propertyName, bean));
}
}
}
private void autowireByType(String beanName, BeanDefinition mbd,
BeanWrapper bw, MutablePropertyValues pvs) {
String[] propertyNames = unsatisfiedObjectProperties(mbd, bw);
for (String propertyName : propertyNames) {
Class<?> requiredType = bw.getPropertyDescriptor(propertyName).getPropertyType();
Map<String, Object> matchingBeans = findMatchingBeans(requiredType);
if (matchingBeans != null && matchingBeans.size() == 1) {
pvs.addPropertyValue(new PropertyValue(propertyName, matchingBeans.values().iterator().next()));
} else {
if (matchingBeans != null && matchingBeans.size() > 1) {
throw new BeansException("给[" + beanName + "]应用自动装配时找到多个符合条件的bean");
}
}
}
}
自动装配,装配的是容器中的其他bean,简单类型(基本类型、字符串等)不包含在这个过程之中,这一层的过滤就是unsatisfiedObjectProperties(...)
做的事情。这里引入了一个模板方法findMatchingBeans(...)
,对多个BeanDefinition
的操作定义在ListableBeanFactory
中,所以只能留给子类去实现。
回到populateBean(...)
,此时我们可以确定没有遗漏任何需要注入的信息,就可以调用applyPropertyValues(...)
执行注入了。
private void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw,
MutablePropertyValues pvs) throws BeansException {
if (pvs == null) return;
MutablePropertyValues deepCopy = new MutablePropertyValues(pvs);
PropertyValue[] pvals = deepCopy.getPropertyValues();
for (int i = 0; i < pvals.length; i++) {
Object value = resolveValueIfNecessary(beanName, mbd, pvals[i].getName(), pvals[i].getValue());
PropertyValue pv = new PropertyValue(pvals[i].getName(), value);
deepCopy.setPropertyValueAtIndex(i, pv);
}
bw.setPropertyValues(deepCopy);
}
这里的实现也分成两部分,首先我们需要确定每一个setter注入的信息是否需要解析,类型转换在这里我们并不关心,因为BeanWrapper
已经处理了这一切,我们关心的是由<ref>
和<list>
代表的情况。这是因为BeanDefinition
此时持有的MutablePropertyValues
是从xml配置文件中解析出来的原始数据,需要进一步的解析才能使用。搞定了这一层,就可以交给BeanWrapper
去完成剩下的故事了。让我们来看看resolveValueIfNecessary(...)
的实现:
private Object resolveValueIfNecessary(String beanName, BeanDefinition mbd,
String argName, Object value) throws BeansException {
// value是指向另一个bean的引用
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
return resolveReference(mbd, beanName, argName, ref);
}
// value是<list>标签定义的列表
else if (value instanceof ManagedList) {
return resolveManagedList(beanName, mbd, argName, (ManagedList) value);
} else {
// 内部bean/map/set等这里就不做支持了
return value;
}
}
上一篇我们创建的标记类型RuntimeBeanReference
和ManagedList
终于派上了用场!解析RuntimeBeanReference
和ManagedList
的方法也很简单,对于RuntimeBeanReference
,获取保存的beanName
对它进行getBean(...)
即可,对于ManagedList
,需要逐个解析它的每一个元素,至此,setter注入的整个流程就宣告结束。
/**
* 解析一个指向其他bean的引用。
*/
private Object resolveReference(BeanDefinition mergedBeanDefinition, String beanName,
String argName, RuntimeBeanReference ref) throws BeansException {
try {
System.out.println("正在解析[" + beanName + "]的[" + argName + "]指向的["+ ref + "]引用");
return getBean(ref.getBeanName());
} catch (BeansException ex) {
throw new BeansException("无法解析[" + beanName + "]的[" + argName + "]指向的["+ ref + "]引用");
}
}
/**
* 解析<list>中的每一个元素
*/
private List<Object> resolveManagedList(String beanName, BeanDefinition mbd,
String argName, ManagedList<?> ml) throws BeansException {
List<Object> resolved = new ArrayList<>();
for (int i = 0; i < ml.size(); i++) {
resolved.add(resolveValueIfNecessary(beanName, mbd, argName + "[" + i + "]", ml.get(i)));
}
return resolved;
}
对于构造函数注入,让我们回到createBean(...)
,找到autowireConstructor(...)
,相对setter注入来说是要复杂一些的。
private BeanWrapper autowireConstructor(String beanName, BeanDefinition mbd) {
// cargs中持有的是未解析的参数
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
// 保存cargs持有的参数对应的解析版本
ConstructorArgumentValues resolvedValues = new ConstructorArgumentValues();
int numberOfCArgs = 0;
if (cargs != null) {
numberOfCArgs = cargs.getNumberOfArguments();
Set<Integer> integerSet = cargs.getIndexedArgumentValues().keySet();
for (int index : integerSet) {
// 支持指定下标和不指定下标的混用
if (index > numberOfCArgs) {
numberOfCArgs = index + 1;
}
// 执行解析并构造镜像版本
ConstructorArgumentValues.ValueHolder valueHolder = cargs.getIndexedArgumentValues().get(index);
Object resolvedValue = resolveValueIfNecessary(beanName, mbd, "ctor arg at " + index, valueHolder.getValue());
resolvedValues.addIndexedArgumentValue(index, resolvedValue, valueHolder.getType());
}
// 执行解析并构造镜像版本
for (ConstructorArgumentValues.ValueHolder valueHolder : cargs.getGenericArgumentValues()) {
Object resolvedValue = resolveValueIfNecessary(beanName, mbd, "ctor generic arg", valueHolder.getValue());
resolvedValues.addGenericArgumentValue(resolvedValue, valueHolder.getType());
}
}
// 获取bean class的所有构造器
Constructor<?>[] constructors = mbd.getBeanClass().getConstructors();
// 按参数个数从多到少排序,方便后续做选择
Arrays.sort(constructors, (c1,c2) -> {
int c1Len = c1.getParameterCount();
int c2Len = c2.getParameterCount();
return c2Len - c1Len;
});
BeanWrapper beanWrapper = new BeanWrapper();
registerPropertyEditors(beanWrapper);
Constructor<?> selectedCtor = null;
Object[] selectedArgs = null;
// 类型的匹配程度
int minTypeDiffWeight = Integer.MAX_VALUE;
// 遍历构造函数,查找第一个匹配的
for (int i = 0; i < constructors.length; i++) {
try {
Constructor constructor = constructors[i];
if (constructor.getParameterTypes().length < numberOfCArgs) {
throw new BeansException("在给[ " + beanName + "]按构造器自动装配时找不到对应的构造函数");
}
Class[] argTypes = constructor.getParameterTypes();
Object[] args = new Object[argTypes.length];
for (int j = 0; j < argTypes.length; j++) {
// 首先看看resolvedValues中是否有符合的
ConstructorArgumentValues.ValueHolder valueHolder = resolvedValues.getArgumentValue(j, argTypes[j]);
if (valueHolder != null) {
// 有的话解析以后可以使用
args[j] = beanWrapper.convertIfNecessary(valueHolder.getValue(), argTypes[i]);
} else {
// 没有的话就要在整个BeanFactory中查看一下有没有类型兼容的了
Map<String, Object> matchingBeans = findMatchingBeans(argTypes[j]);
if (matchingBeans == null || matchingBeans.size() != 1) {
throw new IllegalStateException("使用自动装配时BeanFactory中只能有一个类型兼容的bean。");
}
args[j] = matchingBeans.values().iterator().next();
}
}
int typeDiffWeight = getTypeDifferenceWeight(argTypes, args);
// 可能有多个匹配结果,删选出最精确的那一个
if (typeDiffWeight < minTypeDiffWeight) {
selectedCtor = constructor;
selectedArgs = args;
minTypeDiffWeight = typeDiffWeight;
}
} catch (BeansException ex) {
// 没有合适的
if (i == constructors.length - 1 && selectedCtor == null) {
throw ex;
}
}
}
if (selectedCtor == null) {
throw new BeansException("在[" + beanName + "]中找不到合适的构造函数");
}
// 根据推断的构造器和参数初始化新的对象
beanWrapper.setWrappedInstance(ClassUtils.instantiateClass(selectedCtor, selectedArgs));
return beanWrapper;
}
和setter注入一样,首先也需要做进一步的解析,解析完成之后我们就拥有了可用的构造函数参数——resolvedValues
,接下来的任务就是根据resolvedValues
从bean的所有构造函数中挑选出最匹配的那一个。何为最匹配呢?假如某个类有两个构造函数,一个接受Integer
作为参数,另一个接受Number
作为参数,如果我们传入的参数是Integer
类型,那相对来说接受Integer
作为参数的那一个就比接受Number
作为参数的那一个要匹配。这一部分的逻辑是通过查询在继承体系中的远近关系来确定的,越匹配值越低。了解了这个思路之后,就可以理解for循环中的代码了。
/**
* 用来确定arg和对应argType的远近关系,从来确定匹配结果。
*/
private int getTypeDifferenceWeight(Class<?>[] argTypes, Object[] args) {
int result = 0;
for (int i = 0; i < argTypes.length; i++) {
if (!ClassUtils.isAssignableValue(argTypes[i], args[i])) {
return Integer.MAX_VALUE;
}
if (args[i] != null) {
Class<?> superClass = args[i].getClass().getSuperclass();
while (superClass != null) {
if (argTypes[i].isAssignableFrom(superClass)) {
result++;
superClass = superClass.getSuperclass();
}
else {
superClass = null;
}
}
}
}
return result;
}
看完了bean的创建流程,让我们来关心一下singleton bean的销毁过程:
@Override
public void destroySingleton(String beanName, Object singletonObject) {
BeanDefinition mbd = getBeanDefinition(beanName);
try {
invokeDestroyMethod(singletonObject, mbd);
} catch (Exception e) {
throw new BeansException("无法调用[" + beanName + "]定义的销毁方法");
}
}
private void invokeDestroyMethod(Object bean, BeanDefinition mbd) throws Exception {
if (bean instanceof DisposableBean) {
((DisposableBean) bean).destroy();
}
if (mbd.getDestroyMethodName() != null) {
bean.getClass().getMethod(mbd.getDestroyMethodName()).invoke(bean);
}
}
统一回调了对应的生命周期方法,没有其他内容。至于AbstractAutowireCapableBeanFactory
中的其他内容,都建立在上述的基础之上,各位同学自行翻看就好。
关于DefaultListableBeanFactory
DefaultListableBeanFactory
继承自AbstractAutowireCapableBeanFactory
实现了ConfigurableListableBeanFactory
和BeanDefinitionRegistry
接口,终于完成了大一统,集齐了BeanFactory
的所有功能。有了AbstractAutowireCapableBeanFactory
做基石,DefaultListableBeanFactory
的实现相对来讲是很简单的,私有属性Map<String, BeanDefinition>
就完成了BeanDefinitionRegistry
和ListableBeanFactory
大部分的功能,值得注意的只有preInstantiateSingletons()
和getBeansOfType(...)
两个方法了。
@Override
public void preInstantiateSingletons() {
for (String beanName : beanDefinitionNames) {
if (containsBeanDefinition(beanName)) {
BeanDefinition bd = getBeanDefinition(beanName);
if (bd.isSingleton() && !bd.isLazyInit()) {
if (FactoryBean.class.isAssignableFrom(bd.getBeanClass())) {
FactoryBean factory = (FactoryBean) getBean( FactoryBean.FACTORY_BEAN_PREFIX + beanName);
if (factory.isSingleton()) {
getBean(beanName);
}
} else {
getBean(beanName);
}
}
}
}
}
public Map<String, Object> getBeansOfType(Class<?> type, boolean includePrototypes, boolean includeFactoryBeans) throws BeansException {
String[] beanNames = getBeanDefinitionNames(type);
Map<String, Object> result = new HashMap<>();
for (String beanName : beanNames) {
if (includePrototypes || isSingleton(beanName)) {
result.put(beanName, getBean(beanName));
}
}
String[] singletonNames = getSingletonNames(type);
for (String beanName : singletonNames) {
result.put(beanName, getBean(beanName));
}
if (includeFactoryBeans) {
String[] factoryNames = getBeanDefinitionNames(FactoryBean.class);
for (String factoryName : factoryNames) {
try {
FactoryBean factory = (FactoryBean) getBean(FactoryBean.FACTORY_BEAN_PREFIX + factoryName);
Class objectType = factory.getObjectType();
if ((objectType == null && factory.isSingleton()) ||
((factory.isSingleton() || includePrototypes) &&
objectType != null && type.isAssignableFrom(objectType))) {
Object createdObject = getBean(factoryName);
if (type.isInstance(createdObject)) {
result.put(factoryName, createdObject);
}
}
} catch (BeansException ex) {
System.out.println("从FactoryBean中创建对象失败");
}
}
}
return result;
}
即使是这两个方法,实现也并不复杂,注意不要遗漏有FactoryBean
存在的情况。
XMLBeanFactory
到这里,我们已经拥有了DefaultXMLBeanDefinitionReader
和DefaultListableBeanFactory
,两者组合就是一个相对完整的IoC容器了,XMLBeanFactory
则更进一步,内部进行了组合,为我们提供了便利。
public class XMLBeanFactory extends DefaultListableBeanFactory {
/// MARK - Properties
// xml配置文件读取器
private final XMLBeanDefinitionReader reader = new DefaultXMLBeanDefinitionReader(this);
/// MARK - Initializers
public XMLBeanFactory(Resource resource) throws BeansException {
this.reader.loadBeanDefinitions(resource);
}
}
结语
整个spring-beans的基本逻辑到这里就全部讲解完了,完整代码在tiny-spring。