16-Spring源码解析之Bean的生命周期(1)——doGetBean

Spring版本:<version>5.2.1.RELEASE</version>

上一篇:15-Spring源码解析之refresh(8)——【finishBeanFactoryInitialization】

本篇我们来解决上一篇中遗留的问题,即finishBeanFactoryInitialization中是如何通过getBean来创建Bean实例的。

为了更好更清晰的理解Bean的生命周期。我首先给出一个很简单的例子。这个例子包含:

  • 实体类(User)
    • 实现了InitializingBean 接口,实现这个接口的目的是更好的看afterPropertiesSet方法的执行时机
    • 这个类不包含@Autowired@Value@Resource等注解,因为这些注解需要在Bean创建的时候进行解析,为了更好的理解Bean生命周期的整体逻辑,这里先不额外增加以上注解,后续文章会讲解这些注解在Bean创建中的哪一步起作用。
  • 自定义BeanPostProcessorMyBeanPostProcessor
    • 实现了BeanPostProcessor接口,重写postProcessBeforeInitialization方法和postProcessAfterInitialization方法。
    • 例子中包含这个接口的目的是为了看 postProcessBeforeInitializationpostProcessAfterInitialization的执行时机
  • 配置类(MainConfig)
    • 这个类只有两个注解:
      • @Configuration:标注当前类是配置类的注解,用于标注Spring首先解析的类
      • @ComponentScan:包扫描注解,用于扫描 实现类User和自定义类MyBeanPostProcessor

下面给出这个例子的源代码

一、例子

包结构

在这里插入图片描述

1. 实体类User

package com.spring.csdn;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

@Component
public class User implements InitializingBean {

    private String name;

    public User() {
        System.out.println("User类的 【无参构造器】");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("User类的 【afterPropertiesSet】 方法");
    }
}

2. 自定义BeanPostProcessorMyBeanPostProcessor

package com.spring.postprocessor;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization -> 当前类为:" + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization -> " + beanName);
        return bean;
    }
}

3. 配置类MainConfig

package com.spring.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.spring")
public class MainConfig {

}

4. 测试类Test

package com.spring;

import com.spring.config.MainConfig;
import com.spring.csdn.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        User user = applicationContext.getBean(User.class);
    }
}

5. 输出结果

在这里插入图片描述

我们知道BeanPostProcessor会拦截每个Bean的创建,然后在每个Bean的初始化方法执行前执行postProcessBeforeInitialization,在初始化方法执行后执行postProcessAfterInitialization。所以可以看到输出结果中,回对Spring中的每一个类都执行了postProcessBeforeInitializationpostProcessAfterInitialization方法。 而有关构造器和afterPropertiesSet的执行时机,我们下面来慢慢分析。

二、getBean获取Bean实例

2.1 当前beanFactory中的值

上一篇文章,我们讲到了finishBeanFactoryInitialization方法在最后会调用getBean方法获取Bean实例。那么接下我们就具体看一下它是如何获取到Bean实例的。

在看这个方法之前,我们有必要看一下当前BeanDefinition的情况,以及beanFactory已经创建Bean的情况。

beanDefintion的情况:
在这里插入图片描述

beanFactoryregisteredSingletons属性保存已经创建的Bean的情况。
在这里插入图片描述
从上面图片可以看出当前容器中有12个Bean已经被创建了,其中只有registeredSingletons[9]是我们自己的Bean,其他的都是Spring内部自己创建的Bean,我们暂时不考虑Spring内部自己创建的Bean的作用(因为涉及的内容太多了,有一些已经在前面的文章中讲过了)。

接下来是真正到了看一下finishBeanFactoryInitialization是如何获取到Bean实例的时候了。

2.2 getBean方法

我们以获取User类为例子进行讲解。接着上篇文章,上篇文章在最后finishBeanFactoryInitialization方法调用preInstantiateSingletons方法,preInstantiateSingletons方法在每一个for循环里面调用getBean方法。现在我们就进入getBean方法。

	public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}

它调用的是AbstractBeanFactory类的getBean方法,我们可以看一下AbstractBeanFactory类实际上有4个getBean方法。

在这里插入图片描述
注意,在初始化容器的时候,调用的是getBean(String)方法。但是这里还需要注意的另外一个事情是:虽然AbstractBeanFactory类有4个getBean方法,但是每个方法都调用了doGetBean方法,且AbstractBeanFactorydoGetBean方法只有一个。

	@Override
	public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}
	@Override
	public <T> T getBean(String name, 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);
	}

2.3 doGetBean

高能预警:这个doGetBean做了好多事情,而且代码有点长。

	protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

// ------------------------------------------【功能一】--2.3.1详细介绍----------------------------------------
// ------------------------------------------转换对应 beanName----------------------------------------

		final String beanName = transformedBeanName(name);
		Object bean;

// ------------------------------------------【功能二】--2.3.2详细介绍----------------------------------------
// ------------------------------------------尝试从缓存中加载单例----------------------------------------

		// Eagerly check singleton cache for manually registered singletons.
		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 + "'");
				}
			}
			// -------------------------------------------------------------------------
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}
// ------------------------------------------根据【功能二】返回的结果进行------------------------------------------
		else {
			// Fail if we're already creating this bean instance:
			// We're assumably within a circular reference.
// ------------------------------------------【功能三】------------------------------------------
			// 只有singleton情况下才会尝试解决循环依赖
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}
// ------------------------------------------【功能四】------------------------------------------
			// Check if bean definition exists in this factory.
			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);
				}
			}
// ------------------------------------------【功能五】---2.3.3详细介绍---------------------------------------
			if (!typeCheckOnly) {
				// 将创建的Bean加入到beanFactory的alreadyCreated属性中
				markBeanAsCreated(beanName);
			}
// ------------------------------------------【功能六】------------------------------------------
			try {
				// BeanDfinitiaon定义公共的抽象累是AbstractBeanDefinition。
				// 普通的Bean在Spring注册BeanDefinition的时候,实例化出来的是GenericBeanDefinition
				// Spring内置的Bean在注册BeanDefinition的时候,实例化出来的是RootBeanDefinition,
				// 这时候,就要用getMergedLocalBeanDefinition将所有的BeanDefinition都转换为RootBeanDefinition
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);
// ------------------------------------------【功能七】--寻找依赖----------------------------------------
				// Guarantee initialization of beans that the current bean depends on.
				// 若当前Bean有依赖,则先创建依赖Bean
				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 + "'");
						}
						registerDependentBean(dep, beanName);
						try {
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}
// ------------------------------------------【功能八】核心方法:下一篇文章重点介绍---------------------------------------
				// 针对不同的scope进行bean的创建

				// ---------------------------【Singleton】类型---------------------------
				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 = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}


				// ---------------------------【Prototype】类型---------------------------
				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);
				}

				// ---------------------------【其他Scope】类型---------------------------
				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;
			}
		}
// ------------------------------------------【功能九】------------------------------------------
		// Check if required type matches the type of the actual bean instance.
		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;
	}

在本文的最后会总结doGetBean方法的功能,我们先一步步拆解这里面的每个功能所作的事情。

2.3.1 【功能一】 transformedBeanName

根据这个方法的名字可以知道,该方法的作用是:转换对于的beanName,那这里为什么要转换呢?
实际上,在创建Spring容器的过程中是不需要转换beanName的,因此在创建Spring容器的时候,该方法还是将我们原来的beanName返回。

但是当我们在获取Spring容器之后,自己在程序中调用getBean方法的时候,就可能会用到这个方法。比如我们在程序中写:

public class Test {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        PeopleFactory peopleFactory = (PeopleFactory)applicationContext.getBean("&people");
    }
}

在写applicationContext.getBean();的时候,我们会给getBean方法传入String类型的参数。当获取的bean是一个实现了FactoryBean接口的类的时候,transformedBeanName方法就起作用了。

下面看一下transformedBeanName方法的实现:

	protected String transformedBeanName(String name) {
		return canonicalName(BeanFactoryUtils.transformedBeanName(name));
	}

从上面方法可以看出,transformedBeanName首先调用了BeanFactoryUtils.transformedBeanName

	// BeanFactoryUtils类的transformedBeanName方法
	// String FACTORY_BEAN_PREFIX = "&";
	public static String transformedBeanName(String name) {
		Assert.notNull(name, "'name' must not be null");
		if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
			return name;
		}
		return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
			do {
				beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
			}
			while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
			return beanName;
		});
	}

可以看出,先去除FactoryBean的修饰符&,即如果name = &people,那么会首先除去&而使name = people
返回后transformedBeanName方法又调用canonicalName方法

	public String canonicalName(String name) {
		String canonicalName = name;
		// Handle aliasing...
		String resolvedName;
		do {
			resolvedName = this.aliasMap.get(canonicalName);
			if (resolvedName != null) {
				canonicalName = resolvedName;
			}
		}
		while (resolvedName != null);
		return canonicalName;
	}

2.3.2 【功能二】getSingleton从缓存中加载单例

单例在Spring的同一个容器中只会被创建一次,创建完成后,会把创建好的Bean加入到缓存中。

因此Spring每次在getSingleton获取Bean的时候会先尝试从缓存中加载,如果加载不成功再次从singletonFactories中加载。因为在创建单例Bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,在Spring中创建Bean的时候,执行createBean -> doCreateBean -> createBeanInstance之后,就会将刚实例化好还没有进行属性注入(populate)的Bean加入到缓存中。一旦下一个Bean创建的时候需要依赖上一个Bean,则直接使用ObjectFactory

我们先来看看getSingleton方法所在的类:

在这里插入图片描述
这个类有3个getSingleton方法。而我们从缓存中加载单例是调用的getSingleton(beanName)方法。

下面我们来具体看一下Spring是怎么从缓存中加载单例的。

	public Object getSingleton(String beanName) {
		// 第二个参数设置为true表示:允许早期依赖
		return getSingleton(beanName, true);
	}

它又调用了getSingleton(beanName, true)方法

	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// 检查缓存singletonObjects中是否存在beanName的实例
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				//	如果此Bean正在加载则不处理
				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;
	}
  • singletonObjects:用于保存beanNamebean实例之间的关系
  • singletonFactories:用于保存beanName和创建bean工厂之间的关系
  • earlySingletonObjects:用于保存beanNamebean实例之间的关系,与singletonObjects不同之处在于:当一个单利bean被放到这里面之后,那么当bean还在创建过程种,就可以通过getBean方法获取到了,目的是用来检查循环依赖。
  • registeredSingletons:用于保存当前所有已经创建的bean

2.3.3 【功能五】markBeanAsCreated

走到这一步说明缓存中没有beanName的单例,所以下面要开始创建Bean了,那么在创建之前,我们需要将即将创建的Bean加入到beanFactoryalreadyCreated属性中。

	protected void markBeanAsCreated(String beanName) {
		if (!this.alreadyCreated.contains(beanName)) {
			synchronized (this.mergedBeanDefinitions) {
				if (!this.alreadyCreated.contains(beanName)) {
					// 将RootBeanDefinition的re-merge属性设置为true
					// 因为我们要创建这个bean了,所以以放在创建过程中它的metadata发生变化
					clearMergedBeanDefinition(beanName);
					this.alreadyCreated.add(beanName);
				}
			}
		}
	}

三、总结

doGetBean方法的工作流程:

在这里插入图片描述

doGetBean方法是为了获取bean,首先从缓存中获取,缓存中没有就开始创建Bean,而本篇文章只讲到了从缓存中获取,下一篇文章讲解重头戏,

  • getSingleton -> createBean来创建Bean
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值