在分析源码流程之前,我们先来看一下 FactoryBean
,乍一看这家伙和 BeanFactory
很像,它们都可以用来获取 bean 对象,简单来说 FactoryBean
是一种可以生产 bean 的 bean,而 FactoryBean
是一个生产 bean 的工厂。
下面举个例子来简单说明一下 BeanFactory
的用法:
// 定义一个 User
@Dat
@Builder
public class User {
private String name;
private Integer age;
}
// 定义一个 FactoryBean 用来创建 User 实
public class UserFactoryBean implements FactoryBean<User> {
@Override
public User getObject() {
return User.builder()
.name("jas")
.age(18)
.build();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
// 在 spring 的配置文件中配置 FactoryBean 实
<bean id="userFactoryBean" class="com.jas.mess.factory.UserFactoryBean"/>
// 编写测试类
@Test
public void factoryBeanTest() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(configLocation);
System.out.println("userFactoryBean -> " + applicationContext.getBean("userFactoryBean", User.class));
// & 可以用于获取 FactoryBean 本身
UserFactoryBean userFactoryBean = applicationContext.getBean("&userFactoryBean", UserFactoryBean.class);
System.out.println("&userFactoryBean -> " + userFactoryBean);
System.out.println("userFactoryBean objectType -> " + userFactoryBean.getObjectType());
}
输出结果如下:
从上面的输出结果中可以看出 FactoryBean
可以用来创建其他类型的 bean,如果想要获取 FactoryBean
实例本身,需要给 beanName 加上 &
前缀。
从 Spring IoC 容器获取 bean 的流程里有关于 FactoryBean
的处理,上面知道了 FactoryBean
的用法,下面一起来看下具体的流程细节吧!
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
/**
* 这里的 name 有三种情况:
* 1.beanName 本身,即: 中 id 的值
* 2.'&' 开头,表示获取 FactoryBean 本身
* 3.alias 别名
*
* 如果 beanName 以 `&` 开头,则去除 `&` 前缀,如果是 alias 则替换为对应的 beanName
*/
final String beanName = transformedBeanName(name);
Object bean;
// 单例模式的 Bean 在整个过程中只会被创建一次,第一次创建后会将该 Bean 加载到缓存中,再获取 Bean 就会从缓存中获取
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
/**
* 注意这个 name 是没有经过处理的,有可能以 `&` 开头,即获取 FactoryBean 本身,而不是对应的 bean 实例
* 当然如果是获取 FactoryBean 本身则会直接返回
*/
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
/**
* 因为 Spring 只解决单例模式下得循环依赖,在原型模式下如果存在循环依赖则会抛出异常
* Spring 只能解决单例模式的循环依赖,为什么呢?因为单例模式下有对象缓存
*/
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 单例缓存中没有实例,则可能表明该实例还没有创建或者该实例在父容器中已经创建了,所以需要先检查一次父容器
BeanFactory parentBeanFactory = getParentBeanFactory();
// parentBeanFactory 不为空且 beanDefinitionMap 中已经保存过 beanName 对应的 BeanDefinition
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// 获取 name 对应的 beanName,如果 name 是以 & 字符开头,则返回 & + beanName
String nameToLookup = originalBeanName(name);
// 如果父类容器为 AbstractBeanFactory ,则调用 doGetBean 获取 bean
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
// 用明确的 args 从 parentBeanFactory 中,获取 Bean 对象
else if (args != null) {
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
// 用明确的 requiredType 从 parentBeanFactory 中,获取 Bean 对象
else if (requiredType != null) {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
// 直接使用 beanName 从 parentBeanFactory 获取 Bean 对象
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
if (!typeCheckOnly) {
// 标记 bean 创建完成或将要创建,主要用来缓存
markBeanAsCreated(beanName);
}
try {
// 合并父 BeanDefinition 与子 BeanDefinition(父子容器根据 beanName 进行属性合并)
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 检查给定的合并的 beanDefinition
checkMergedBeanDefinition(mbd, beanName, args);
// 获取依赖的 bean
String[] dependsOn = mbd.getDependsOn();
/**
* 每个 Bean 都不一定是单独工作的,它可能会依赖其他 Bean,其他 Bean 也会依赖它
* 对于依赖的 Bean ,它会优先加载,所以,在 Spring 的加载顺序中,
* 在初始化某一个 Bean 的时候,首先会初始化这个 Bean 的依赖
*
* 注意这种依赖不是 bean 属性相互依赖,与我们常说的循环依赖是两种类型
*
*
*
*
*
* 对于上面这种依赖关系会抛出异常
*/
if (dependsOn != null) {
for (String dep : dependsOn) {
// 如果存在循环依赖,则抛出异常
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// 注入依赖的 bean 存储在对应的 map 中,记录彼此依赖的关系
registerDependentBean(dep, beanName);
try {
// 内部通过调用 doGetBean 方法 加载 depends-on 依赖的 bean
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
/**
* Spring Bean 的作用域默认为 singleton ,当然还有其他作用域,如 prototype、request、session 等
* 不同的作用域会有不同的初始化策略
* 如果是单例模式,因为刚开始是从单例缓存中获取,如果缓存中不存在,则需要从头开始加载
*/
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
// 处理 FactoryBean 类型的 bean
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 原型模式
else if (mbd.isPrototype()) {
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// 从指定的 scope 下创建 bean
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// 检查 bean 的实际类型是否符合需要的类型
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
getBean 的主要流程就是上面这些,下面根据步骤来总结一下,对于一些比较重要的方法,下面会进行详细分析。
&
开头,则剥离 &
前缀下面对一些重要的方法单独拿出来分析,帮助大家理解。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
getSingleton
方法涉及到循环依赖问题,有兴趣的可以找下上篇文章,有详细解释。这里涉及到三个缓存 map,其中有一个就是用来解决循环依赖的,这里分别介绍一下。
earlySingletonObjects
中)以后,会删除该缓存,可以用来解决循环依赖在一开始的时候我们先了解了 FactoryBean
,下面的逻辑就会处理到。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// 判断 nam 是否以 '&' 开头,如果是表示获取 FactoryBean 本身,而不是对应的 bean 实例
if (BeanFactoryUtils.isFactoryDereference(name)) {
// 如果是 NullBean 直接返回
if (beanInstance instanceof NullBean) {
return beanInstance;
}
// 已 & 开头,如果不是 FactoryBean 类型抛出异常
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
}
// 该实例可能是会是一个正常的 bean 又或者是一个 FactoryBean 本身,如果是则直接返回
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
/**
* 如果 beanDefinition 为 null,则从 factoryBeanObjectCache 缓存中获取 bean
* FactoryBean 生成的单例 bean 会被缓存在 factoryBeanObjectCache 集合中,不用每次都创建
*/
if (mbd == null) {
object = getCachedObjectForFactoryBean(beanName);
}
// 如果代码执行这里则可以确认,beanInstance 一定是 FactoryBean 类型
if (object == null) {
// 转换成 FactoryBean 类型
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
// 将存储 XML 配置文件的 GenericBeanDefinition 转换为 RootBeanDefinition,
// 合并 BeanDefinition
mbd = getMergedLocalBeanDefinition(beanName);
}
// 检测是用户定义的还是程序本身定义的
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 从 FactoryBean 中获取实例
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
FactoryBean
类型,如果以 &
开头切不是 FactoryBean
类型抛出异常BeanFactory
本身,则直接返回FactoryBean
中获取实例getObjectFromFactoryBean
方法还有一些流程,这里就不赘述了,有兴趣的自己可以研究下。
Spring IOC 容器源码分析 - 获取单例 bean by 田小波