spring获取bean的源码解析
作者:not back 发布时间:2023-10-11 22:15:43
介绍
前面一章说了AbstractApplicationContext中的refresh方法中的invokeBeanFactoryPostProcessors。主要是调用BeanFactoryPostProcessor。其中也有获取bean的过程,就是beanFactory.getBean的方法。这一章就说下getBean这个方法。由于spring中获取bean的方法比较复杂,涉及到的流程也非常多,这一章就先说下整个大体的流程。其中的细节会在后面也会慢慢说。
源码
直接看源码吧
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
@Override
public <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}
@Override
public Object getBean(String name, Object... args) throws BeansException {
return doGetBean(name, null, args, false);
}
public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args)
throws BeansException {
return doGetBean(name, requiredType, args, false);
}
@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 把name转化成beanName,也就是把FactoryBean的名称转化成beanName如果有别名则用别名
final String beanName = transformedBeanName(name);
Object bean;
// 从缓存中获取实例
// 可能是需要的Bean实例,也可能是FactoryBean
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 获取需要的bean或者FactoryBean
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 判断prototype类型的bean是否存在循环引用
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 校验父类BeanFactory
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// 父类去获取bean
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 {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
// 标记成已创建
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
// 把原来BeanDefinition转换成RootBeanDefinition
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// 获取依赖的bean,也就是通过@DependsOn注入进来的bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
// 校验dependsOn的bean是否存在循环应用
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// 加入到引用的缓存中,由于校验dependsOn循环引用
registerDependentBean(dep, beanName);
// 获取@dependsOn的bean
getBean(dep);
}
}
// 创建单例的bean
if (mbd.isSingleton()) {
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或者FactoryBean
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 创建prototype的bean
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// 创建其他的bean,比如session,request等
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.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
获取bean的整体流程就像上面源码所示,这里再梳理下spring获取bean的整个流程
1.先转换bean的名称,转换成beanName。这里意思就是,我们在获取bean的时候,可能是FactoryBean的名称(&开头),这里转成不带&开头的名称,如果有别名,再获取别名。
2.从缓存中获取bean,这里的缓存分为一二 * 缓存,也就是我们常常被问到了spring * 缓存,具体逻辑下面再说。
3.根据获取的到对象再去获取我们想要的bean,因为这里获取到的对象可能是我们需要的bean,也可能是FactoryBean。
4.如果缓存中没有,那么我们就要自己去创建bean了。
5.查看有没有父类的BeanFactory,如果有,那么就父类去创建bean。
6.获取要创建的bean对象的@DependsOn注解上的名称,先去创建DependsOn的bean,并且校验是否存在循环引用
7.创建bean,根据类型创建不同的bean,比如singleton,prototype,request,session等。
8.如果需要转换类型,则进行类型转换。
整体的获取bean的流程就是这样了,其中有些具体流程接着分析。
从缓存中获取bean对象
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
@Nullable
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;
}
spring通过 * 缓存来解决循环依赖的问题。简单来介绍下 * 缓存。
1. singletonObjects为一级缓存,我们实例化的bean都在这个map里,侠义的说singletonObjects才是我们真正的spring容器,存放bean的地方。
2. earlySingletonObjects为二级缓存,是存放未完成的bean的缓存,如果有代理的话,存放的是代理对象。
3. singletonFactories为 * 缓存,存放的是一个ObjectFactory,数据通过getObject方法获得。
从BeanInstance中获取对象
接下来看getObjectForBeanInstance方法。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// name是不是factoryBean的name(&开头的)
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
// 如果是FactoryBeanName,但是获取到的bean不是FactoryBean,则抛异常
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
}
// 如果bean不是FactoryBean,或者名称是FactoryBeanName,直接返回BeanInstace
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
// 从缓存中获取
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// 这里可以确定beanInstance是FactoryBean了
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());
// 通过FactoryFBean中获取需要的beanInstance
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
这里是通过BeanInstance获取我们想要的bean,这里也简单说下流程
1. 首先判断name是不是FactoryBean的name,也就是&开头的name,如果是去判断beanInstance是不是FactoryBean,如果beanInstance不是FactoryBean则抛异常。
2. 由于上面已经判断过,如果name是FactoryBeanName,但是BeanInstance不是FactoryBean的话,就会抛出异常。所以如果BeanInstance如果不是FactoryBean的话,那么name一定不是FactoryBeanName。那么就直接返回BeanInstance就是我们需要的了。
如果name是FactoryBeanName,那么我们需要获取的就是FactoryBean,也直接返回就可以了。
3. 如果都没有返回,那么已经可以确定我们此时的已经可以确定BeanInstance是FactoryBean了,因为如果不是FactoryBean的话,在!(beanInstance instanceof FactoryBean)就已经返回了。
4. 通过FactoryBean的getObject方法获取我们需要的bean实例。
创建bean
根据@dependsOn查找依赖的bean并且加到依赖里面去没有什么好说的,代码逻辑也很简单,接下来看创建单例bean。其他类型的bean的创建也都差别不大。看源码
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(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
// 在没创建bean之前的处理
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 获取创建的bean
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// 创建结束之后的工作
afterSingletonCreation(beanName);
}
if (newSingleton) {
// 加到一级缓存中,其实也就是真正的容器中了
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
对于创建单例bean的主要流程就是如此,传入一个beanName,和一个ObjectFactory。ObjectFactory中具体实现了创建bean的逻辑。在看具体创建bean的逻辑之前,我们还需要去看下getSingleton中的创建bean之前的工作和创建bean之后的工作。这里面就是查找bean的循环依赖的方法(和dependsOn不同)。主要是查找根据filed,set,构造器方法的循环依赖。
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}
可以看到代码非常的简单,就是创建bean之前,如果没有排除依赖检查,那么就加入到正在创建的Set中,如果加入不进去,说明之前已经加过,这就产生了循环依赖,从而抛出异常。
如果在创建bean之后,没有排除检查依赖,并且移除失败,说明已经不在Set中,也会抛出异常。
来源:https://blog.csdn.net/xby7437/article/details/116059853
猜你喜欢
- 一、实现原理使用MockMvc发起请求,然后执行API中相应的代码,在执行的过程中使mock模拟底层数据的返回,最后结果验证。二、常用注解介
- 前言用户注册功能是每一个系统的入口门面功能,很多人可能会以为很简单,不就是一个简单的CRUD吗?其实不然,要把前后端功能都做出来,页面跳转也
- 前言Android提供了很多种保存应用程序数据的方法。其中一种就是用SharedPreferences对象来保存我们私有的键值(key-va
- 1.需求背景需要实现一个动态加载但不显示出来的视图,且该视图上有个动态生成的二维码,最后用其去生成一张快照(也就是图片)。(常见这种情况是来
- 单元测试单元测试就是针对最小的功能单元编写测试代码,Java程序最小的功能单元是方法,因此,单元测试就是针对Java方法的测试,进而检查方法
- 1.获取签名与模板进入阿里云平台,进入短信服务模块,在以下位置添加签名和模板(格式一定按照要求填写 审批的比较严格)2.编写模板与签名的枚举
- Sentinel是阿里巴巴开源的限流器熔断器,并且带有可视化操作界面。在日常开发中,限流功能时常被使用,用于对某些接口进行限流熔断,譬如限制
- JdbcTypeInterceptor运行时自动添加 jdbcType 属性 * 签名@Intercepts({
- 最近有个需求,需要统计APP的在线人数,其实以前也统计过,采取的是上线发送一个请求$this->cache->incr()加1,
- 在写接口实现时,有时会有多个实现类。这篇文章介绍在调用时通过传入字符串来指定具体的实现类。一.接口与实现类:// 接口public inte
- (注意:本文基于JDK1.8) 前言包括迭代器中的remove()方法,以及删除单个元素、删除多个元素、删除所有元素、删除不包含的
- 前言static和final是两个我们必须掌握的关键字。不同于其他关键字,他们都有多种用法,而且在一定环境下使用,可以提高程序的运行性能,优
- 讲这个例子前,咱们先来看一个简单的程序:字符串数组实现数字转字母:#include <stdio.h>#include <
- 最近有时间,写一些很简单、很基础的东西,主要在操作层面。主要考虑如下: 1、经常搭建开发环境,所以有必要记录一下,自己也可以备查; 2、给新
- spring in action第三版读书笔记spring3.0引入了spring expression language(spel)语言,
- 方式1:1. 明确 Spark中Job 与 Streaming中 Job 的区别1.1 Spark Core一个 RDD DAG Graph
- 半藏商城中会有一些用户提交了订单但是一直没有支付的情况,之前我是通过quartz定时任务每天的5点扫描未支付订单然后读取用户的邮箱地址发送邮
- 无论是我们在使用word还是记事本,系统都会为我们提供撤销的功能,这几乎是人人都会使用到的功能,而在我们实际开发中,会不会存在一个很复杂的对
- 一、int还记得 C 语言里的 int 吗,C里面的 int 有着无符号与有符号之分但是Java内就没有,且固定占4个字节大小,也就是32比
- 什么是Aop主要介绍springboot中aop的使用,用过Spring框架的都知道,aop是spring框架的两大核心功能之一,还有一个就