前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring5 源码学习 (9) doGetBean 概述

Spring5 源码学习 (9) doGetBean 概述

作者头像
Coder小黑
发布2019-12-18 14:52:30
3910
发布2019-12-18 14:52:30
举报
文章被收录于专栏:Coder小黑Coder小黑

接上回,AbstractApplicationContext#refresh调用AbstractApplicationContext#finishBeanFactoryInitialization来初始化所有的非懒加载单例 Bean。在该AbstractApplicationContext#finishBeanFactoryInitialization方法内部通过调用AbstractBeanFactory#doGetBean来获取 Spring 容器所管理的 Bean。

AbstractBeanFactory#doGetBean

AbstractBeanFactory#doGetBean源码如下:

代码语言:javascript
复制
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
						  @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

	// 如果这个 name 是 FactoryBean 的beanName (&+beanName),就删除& , 返回beanName ,传入的name也可以是别名,也需要做转换
	// 注意 beanName 和 name 变量的区别,beanName是经过处理的,经过处理的beanName就直接对应singletonObjects中的key
	final String beanName = transformedBeanName(name);
	Object bean;

	// Eagerly check singleton cache for manually registered singletons.
	// 根据beanName尝试从singletonObjects获取Bean
	// 获取不到则再尝试从earlySingletonObjects,singletonFactories 从获取Bean
	// 这段代码和解决循环依赖有关
	Object sharedInstance = getSingleton(beanName);
	// 第一次进入sharedInstance肯定为null
	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 + "'");
			}
		}
		// 如果sharedInstance不为null,也就是非第一次进入
		// 为什么要调用 getObjectForBeanInstance 方法,判断当前Bean是不是FactoryBean,如果是,那么要不要调用getObject方法
		// 因为传入的name变量如果是(&+beanName),那么beanName变量就是(beanName),也就是说,程序在这里要返回FactoryBean
		// 如果传入的name变量(beanName),那么beanName变量也是(beanName),但是,之前获取的sharedInstance可能是FactoryBean,需要通过sharedInstance来获取对应的Bean
		// 如果传入的name变量(beanName),那么beanName变量也是(beanName),获取的sharedInstance就是对应的Bean的话,就直接返回Bean
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	} else {
		// Fail if we're already creating this bean instance:
		// We're assumably within a circular reference.
		// 判断是否循环依赖
		if (isPrototypeCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}

		// Check if bean definition exists in this factory.
		// 获取父BeanFactory,一般情况下,父BeanFactory为null,如果存在父BeanFactory,就先去父级容器去查找
		BeanFactory parentBeanFactory = getParentBeanFactory();
		if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
			// Not found -> check parent.
			String nameToLookup = originalBeanName(name);
			if (parentBeanFactory instanceof AbstractBeanFactory) {
				return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
						nameToLookup, requiredType, args, typeCheckOnly);
			} else if (args != null) {
				// Delegation to parent with explicit args.
				return (T) parentBeanFactory.getBean(nameToLookup, args);
			} else if (requiredType != null) {
				// No args -> delegate to standard getBean method.
				return parentBeanFactory.getBean(nameToLookup, requiredType);
			} else {
				return (T) parentBeanFactory.getBean(nameToLookup);
			}
		}

		// 创建的Bean是否需要进行类型验证,一般情况下都不需要
		if (!typeCheckOnly) {
			// 标记 bean 已经被创建
			markBeanAsCreated(beanName);
		}

		try {
			// 获取其父类Bean定义,子类合并父类公共属性
			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			checkMergedBeanDefinition(mbd, beanName, args);

			// Guarantee initialization of beans that the current bean depends on.
			// 获取当前Bean依赖的Bean的名称 ,@DependsOn
			String[] dependsOn = mbd.getDependsOn();
			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依赖其他Bean,把被依赖Bean注册给当前Bean
					registerDependentBean(dep, beanName);
					try {
						// 先去创建所依赖的Bean
						getBean(dep);
					} catch (NoSuchBeanDefinitionException ex) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
					}
				}
			}

			// Create bean instance.
			if (mbd.isSingleton()) {
				// 创建单例Bean
				sharedInstance = getSingleton(beanName, () -> {
					try {
						return createBean(beanName, mbd, args);
					} catch (BeansException ex) {
						// Explicitly remove instance from singleton cache: It might have been put there
						// eagerly by the creation process, to allow for circular reference resolution.
						// Also remove any beans that received a temporary reference to the bean.
						destroySingleton(beanName);
						throw ex;
					}
				});
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			} else if (mbd.isPrototype()) {
				// It's a prototype -> create a new instance.
				// 创建prototype Bean,每次都会创建一个新的对象
				Object prototypeInstance = null;
				try {
					// 回调beforePrototypeCreation方法,注册当前创建的原型对象
					beforePrototypeCreation(beanName);
					// 创建对象
					prototypeInstance = createBean(beanName, mbd, args);
				} finally {
					// 回调 afterPrototypeCreation 方法,告诉容器该Bean的原型对象不再创建
					afterPrototypeCreation(beanName);
				}
				bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
			} else {
				// 如果既不是单例Bean,也不是prototype,则获取其Scope
				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;
		}
	}

	// Check if required type matches the type of the actual bean instance.
	// 对创建的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;
}

主要流程都已经在上述的源码中增加了注释,读者可以自己查阅。其中,我觉得最主要是要明白以下几点:

Object sharedInstance = getSingleton(beanName);

Object sharedInstance = getSingleton(beanName);这段代码是解决循环依赖的关键,先大概看一下,留个印象,具体的等后面有空讲一下循环依赖吧。

代码语言:javascript
复制
public Object getSingleton(String beanName) {
	return getSingleton(beanName, true);
}

//getSingleton(beanName, true);源码
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	//singletonObjects 就是Spring内部用来存放单例Bean的对象池,key为beanName,value为Bean
	Object singletonObject = this.singletonObjects.get(beanName);
	// singletonsCurrentlyInCreation 存放了当前正在创建的bean的BeanName
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		synchronized (this.singletonObjects) {
			// earlySingletonObjects 是早期单例Bean的缓存池,此时Bean已经被创建(newInstance),但是还没有完成初始化
			// key为beanName,value为Bean
			singletonObject = this.earlySingletonObjects.get(beanName);
			//是否允许早期依赖
			if (singletonObject == null && allowEarlyReference) {
				//singletonFactories 单例工厂的缓存,key为beanName,value 为ObjectFactory
				ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
				if (singletonFactory != null) {
					//获取早期Bean
					singletonObject = singletonFactory.getObject();
					//将早期Bean放到earlySingletonObjects中
					this.earlySingletonObjects.put(beanName, singletonObject);
					this.singletonFactories.remove(beanName);
				}
			}
		}
	}
	return singletonObject;
}

transformedBeanName 和 getObjectForBeanInstance 的作用

调用doGetBean方法时会传入name变量,表明需要从容器中获取那个 Bean。transformedBeanName除了在处理别名之外,这里会有以下几种情况:

第一种情况,直接往容器中注册 Bean。
代码语言:javascript
复制
@Bean
public UserBean userBean() {
	return new UserBean("shen", 111);
}

在这种情况下,name变量如果为userBean,那么就是要从容器中获取UserBean对象。

调用transformedBeanName方法返回beanName对象的取值userBean

然后根据beanName去容器中获取相应的Bean,而获取到的就是UserBean对象。

最后调用getObjectForBeanInstance方法,返回的还是UserBean对象。

第二种情况,通过FactoryBean往容器中注册 Bean
代码语言:javascript
复制
@Bean
public FactoryBean userBean() {
	return new FactoryBean<UserBean>() {
		@Override
		public UserBean getObject() throws Exception {
			return new UserBean("shen", 111);
		}

		@Override
		public Class<?> getObjectType() {
			return UserBean.class;
		}
	};
}

这里又可以分为两种情况:

第一种情况:

如果name变量如果为userBean,那么也要从容器中获取UserBean对象。

调用transformedBeanName方法返回beanName对象的取值为userBean

然后根据beanName去容器中获取相应的Bean,而获取到的是FactoryBean对象。

最后调用getObjectForBeanInstance方法,发现是从容器中获取UserBean对象,于是调用FactoryBean#getObject返回UserBean对象。

第二种情况:

name变量如果为&userBean,那么就是要从容器中获取FactoryBean对象本身。

调用transformedBeanName方法返回beanName对象的取值为userBean

然后根据beanName去容器中获取相应的Bean,而获取到的是FactoryBean对象,

最后调用getObjectForBeanInstance方法,就是要获取FactoryBean对象,于是方法返回FactoryBean对象。

@DependsOn

通过源码可以知道,Spring 在创建 Bean 之前,首先会创建当前 Bean 所有依赖的 Bean。

代码语言:javascript
复制
String[] dependsOn = mbd.getDependsOn();
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依赖其他Bean,把被依赖Bean注册给当前Bean
		registerDependentBean(dep, beanName);
		try {
			// 先去创建所依赖的Bean
			getBean(dep);
		} catch (NoSuchBeanDefinitionException ex) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
		}
	}
}

那什么是当前 Bean 所有依赖的 Bean 呢?也就是说,String[] dependsOn = mbd.getDependsOn();什么情况下这个数组中会有值呢?

在 Spring 中有这个一个注解:@DependsOn。这个注解一般用的很少(碰巧最近项目中用到了这个注解,哈哈哈)。来看一下 Spring 文档中是怎么描述的:

Beans on which the current bean depends. Any beans specified are guaranteed to be created by the container before this bean. Used infrequently in cases where a bean does not explicitly depend on another through properties or constructor arguments, but rather depends on the side effects of another bean's initialization. A depends-on declaration can specify both an initialization-time dependency and, in the case of singleton beans only, a corresponding destruction-time dependency. Dependent beans that define a depends-on relationship with a given bean are destroyed first, prior to the given bean itself being destroyed. Thus, a depends-on declaration can also control shutdown order. 机器翻译:当前 bean 所依赖的 bean。任何指定的 bean 都保证在此 bean 之前由容器创建。当一个 bean 不是通过属性或构造函数参数显式依赖于另一个 bean,而是依赖于另一个 bean 初始化的副作用时,很少使用。依赖项声明既可以指定初始化时间依赖项,也可以指定(在只有单例 bean 的情况下)对应的销毁时间依赖项。在销毁给定 bean 之前,首先销毁定义与给定 bean 的依赖关系的依赖 bean。因此,依赖声明也可以控制关机顺序。

举个例子
代码语言:javascript
复制
@Service
public class OrderService {

	public OrderService() {
		System.out.println("OrderService create");
	}


	@PreDestroy
	public void destroy() {
		System.out.println("OrderService destroy");
	}
}
代码语言:javascript
复制
@DependsOn("orderService")
@Service
public class UserService {

	public UserService() {
		System.out.println("UserService create");
	}


	@PreDestroy
	public void destroy() {
		System.out.println("UserService destroy");
	}
}
代码语言:javascript
复制
@Configuration
@ComponentScan
public class DependsOnMain {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext context =
				new AnnotationConfigApplicationContext(DependsOnMain.class);
		context.close();
	}
}
代码语言:javascript
复制
//运行结果
OrderService create
UserService create
UserService destroy
OrderService destroy

createBean(beanName, mbd, args);

在 Spring 中存在着多种 Scope,Spring 会根据不用的 Scope 选用不同的初始化方式。但是,不管怎么样,Spring 在底层创建 Bean 的时候都是通过调用AbstractAutowireCapableBeanFactory#createBean方法来创建对象的。

那 Spring 究竟是怎么创建 Bean 的呢?AbstractAutowireCapableBeanFactory#createBean方法内部到底做了什么事情呢?循环依赖该怎么解决呢?

未完待续...


源码注释 GITHUB 地址:https://github.com/shenjianeng/spring-code-study

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-10-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Coder小黑 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • AbstractBeanFactory#doGetBean
    • Object sharedInstance = getSingleton(beanName);
      • transformedBeanName 和 getObjectForBeanInstance 的作用
        • 第一种情况,直接往容器中注册 Bean。
        • 第二种情况,通过FactoryBean往容器中注册 Bean
      • @DependsOn
        • 举个例子
      • createBean(beanName, mbd, args);
      相关产品与服务
      容器服务
      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档