之前谈了有关bean 加载的大致过程。现在要仔细研究一下其中使用到的各个部分的内部原理。
FactoryBean
通常来说,Spring 通过反射机制利用 bean 的 class 属性实现类的加载实例化 bean。但在某些情况下,bean 的实例化比较复杂,需要更为灵活的配置方式,通过自定义编码会更好一些,FactoryBean 就是这样一个工厂类接口,用户可以通过实现 org.springframework.beans.factory.FactoryBean
接口定制实例化 bean 的逻辑。接口的源码如下。
public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}
- T getObject():返回由工厂创建的 bean 实例,如果是单例,则该实例会放到 Spring 容器中但是你缓存池中。
- boolean isSingleton():返回工厂创建的实例是单例还是原型。
- Class<?> getObjectType():返回 FactoryBean 创建的 bean 类型。
若在 bean 标签配置的 class 属性是 FactoryBean,那么最后 Spring 会调用 getObjectType()
方法返回最终结果。
缓存中获取单例 bean
首先我们看看源码。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 直接检查在缓存中是否存在实例
// Quick check for existing instance without full singleton lock
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 缓存中没有,但正在创建,就从早期缓存中寻找
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 还是没有找到,锁定缓存空间,开始创建
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
// 再次检查缓存
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 再次检查早期缓存
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
// 看看工厂缓存中有没有
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 有工厂缓存,用工厂实例化
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
// earlySingletonObjects 和 singletonFactories互斥
// 早期缓存中有工厂就需要被销毁了
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
总结一下,缓存获取就是按顺序在三个缓存里寻找需要的 bean,顺序为 singletonObjects
、earlySingletonObjects
、singletonFactories
,如果最终没有找到,那就直接返回 null。三个缓存的作用解释如下:
- singletonObjects: 用于保存 BeanName 和创建 bean 实例之间的关系,即
bean name
到bean instance
的映射。 - singletonFactories:用于保存 BeanName 和创建 bean 的工厂之间的关系,即
bean name
到ObjectFactory
的映射。 - earlySingletonObjects: 也是保存 BeanName 和创建 bean 实例之间的关系,与
singletonObjects
的区别是当单例还在创建的时候,就可以放入当前缓存了,目的是为了检测循环应用。
从 bean 实例中获取对象
获取的 bean 实例可能是真正的实例也可能是 FactoryBean,如果是实例则直接返回,否则工厂创建。下面是具体源码。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// 如果是指定要 FactoryBean,但是实例不是 FactoryBean 则抛出异常
// Don't let calling code try to dereference the factory if the bean isn't a factory.
if (BeanFactoryUtils.isFactoryDereference(name)) {
// 若是空 bean,则直接返回
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
}
// 如果是 FactoryBean,且 beanName 有 & 前缀,那么直接返回
// 如果不是 FactoryBean,直接返回
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
// 通过工厂创建 bean
Object object = null;
if (mbd == null) {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
总结一下流程:
- FactoryBean 的验证
- 对非 FactoryBean 不作处理
- 对 bean 进行转换
- 将从 Factory 中解析 bean 的工作委托给 getObjFromFactoryBean,也就是调用 getObject() 方法。
获取单例
通过以下源码获取单例。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(...);
}
...
// 记录加载状态
beforeSingletonCreation(beanName);
boolean newSingleton = false;
...
try {
// 调用工厂实例化 bean
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
...
}
catch (BeanCreationException ex) {
...
}
finally {
...
// 清除状态
afterSingletonCreation(beanName);
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
总结一下,上述源码大致可以分为如下几步:
- 检查缓存是否已经加载过;
- 若没有加载,则记录 beanName 正在加载的状态;
- 加载单例前记录加载状态;
将当前正要创建的 bean 记录到缓存中,这样便可以对循环依赖进行检测。 - 通过调用参数中的 ObjectFactory 实例化 bean;
- 加载单例后的处理方法调用;
移出缓存中当前 bean 的正在加载状态。 - 将结果记录到缓存并删除加载 bean 过程中所记录的各种状态;
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
- 返回处理结果
准备创建 bean
首先看一下源码
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
...
RootBeanDefinition mbdToUse = mbd;
// 确保 class 解析完成
// Make sure bean class is actually resolved at this point, and
// clone the bean definition in case of a dynamically resolved Class
// which cannot be stored in the shared merged bean definition.
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
...
// Prepare method overrides.
try {
// 处理 override 属性
mbdToUse.prepareMethodOverrides();
}
...
try {
// 应用初始化前的处理器,解析指定 bean 是否存在初始化前的短路操作
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
...
try {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
...
return beanInstance;
}
...
}
总结一下步骤:
- 根据设置的 class 属性或者根据 className 来解析 Class;
- 对 override 属性进行标记及验证;
- 应用初始化前的处理器,解析指定 bean 是否存在初始化前的短路操作;
- 创建 bean。
处理 override 属性
源码如下
protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
// 获取对应类中方法名的个数
int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
if (count == 0) {
throw new BeanDefinitionValidationException(
"Invalid method override: no method with name '" + mo.getMethodName() +
"' on class [" + getBeanClassName() + "]");
}
else if (count == 1) {
// Mark override as not overloaded, to avoid the overhead of arg type checking.
mo.setOverloaded(false);
}
}
这里并没有做什么更多的操作,只是判断了有多少个 override 属性,即多少个 lookup-method 和 replace-method 配置。
值得注意的是,对于方法的匹配来说,如果一个类中存在若干个重载方法,那么就需要在调用的时候进行参数匹配。这里 Spring 提前做了匹配。
实例化的前置处理
主要是调用 applyBeanPostProcessorsBeforeInstantiation()
和 applyBeanPostProcessorsAfterInitialization()
。其中实例化前的后处理器是为了给子类一个修改 BeanDefinition 的机会。实例化后的后处理器调用主要是因为 bean 可能在实例化前的后置处理器中已经初始化了,之后就不会再进入上层函数的实例化后的后置处理器,这里需要提前调用一次。
这里提到了后置处理器,这个主要是 Spring 为了给用户提供扩展的。
至此,bean 创建的准备工作才算做完了,我们可以继续看看创建 bean 的实际内容了。bean 创建.