spring容器之开启bean的创建之旅
在上篇spring容器之不同scope bean的创建我们在处理原型的过程中遗留了#createBean(String beanName, RootBeanDefinition mbd, Object[] args)方法的讲解,本篇来说一下此方法,该方法为创建bean的入口,直接看代码:
AbstractBeanFactory.java
protected abstract Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException;
这是方法的定义,其中需要三个参数我们分别来说一下参数的用途:
- beanName:该参数为创建bean的名字
- mbd:合并之后的beanDefinition对象
- args:用于构造函数或者工厂方法创建 Bean 实例对象的参数
看完了方法的定义及每个参数的用途,接下来看它的默认实现类AbstractAutowireCapableBeanFactory
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {if (logger.isTraceEnabled()) {
logger.trace("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// 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.
//根据rootBeanDefinition和beanName去解析bean的class
//1.如果当前bean的class被解析了
//1.1. 克隆一份beanDefinition,主要是因为该动态解析的 class 无法保存到到共享的 BeanDefinition
Class> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}//2.覆盖了RootBeanDefinition的prepareMethodOverrides方法
try {
//验证及准备覆盖的方法
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}try {
//3. 获取一个解析之后的代理bean的实例,而不是真正的bean实例
//给 BeanPostProcessors 一个机会用来返回一个代理类而不是真正的类实例
//AOP是基于此处实现的
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}try {
//4.这里才是真正的执行创建bean的方法
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// A previously detected exception with proper bean creation context already,
// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
从代码中我们大致的分为了4个步骤来完成的,这里简单的总结一下
- 通过我们的参数rootBeanDefinition和beanName来解析指定的class
//根据rootBeanDefinition和beanName去解析bean的class
//1.如果当前bean的class被解析了
//1.1. 克隆一份beanDefinition,主要是因为该动态解析的 class 无法保存到到共享的 BeanDefinition
Class> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
我们跟踪代码来到:
AbstractBeanFactory.java
/**
* 1.该方法主要的作用是从bean的定义文件中解析bean的class
* 2.将bean类名解析为class的引用
* @param mbd 从合并的beanDefinition来确定bean的class
* @param beanName bean的名称
* @param typesToMatch 类型是否匹配
* @return解析后的bean的class文件
* @throws CannotLoadBeanClassException
*/
@Nullable
protected Class> resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class>... typesToMatch)
throws CannotLoadBeanClassException {try {
//1.判断是否该bean类型的class,如果是返回class
if (mbd.hasBeanClass()) {
return mbd.getBeanClass();
}
//2. 如果当前解析环境有安全管理器,那么就在此环境下进行bean的class解析
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged((PrivilegedExceptionAction>) () ->
doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
}
//3.没有安全管理器,直接去解析class
else {
return doResolveBeanClass(mbd, typesToMatch);
}
}
catch (PrivilegedActionException pae) {
ClassNotFoundException ex = (ClassNotFoundException) pae.getException();
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
}
catch (ClassNotFoundException ex) {
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
}
catch (LinkageError err) {
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);
}
}
该方法是解析class的过程,简单的来看一下流程<1>. 首先通过rootBeanDefinition#hasBeanClass()判断该bean是否有class,有的话返回即可
<2>. 获取当前解析环境的安全管理器,在此环境下进行解析class的操作
private Class> doResolveBeanClass(RootBeanDefinition mbd, Class>... typesToMatch)
throws ClassNotFoundException {
//获取当前上下文的类加载器
ClassLoader beanClassLoader = getBeanClassLoader();
ClassLoader dynamicLoader = beanClassLoader;
boolean freshResolve = false;
//类型检查
if (!ObjectUtils.isEmpty(typesToMatch)) {
// When just doing type checks (i.e. not creating an actual instance yet),
// use the specified temporary class loader (e.g. in a weaving scenario).
//获取临时的bean的class加载器,用来临时解析bean的class
ClassLoader tempClassLoader = getTempClassLoader();
if (tempClassLoader != null) {
dynamicLoader = tempClassLoader;
freshResolve = true;
//tempClassLoader是否是DecoratingClassLoader(用来装饰class加载器)类型的
if (tempClassLoader instanceof DecoratingClassLoader) {
DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
//遍历所有的类型
//获取类型的类名
//通过获取到的类名去从dcl排除添自己加
for (Class> typeToMatch : typesToMatch) {
dcl.excludeClass(typeToMatch.getName());
}
}
}
}
//typesToMatch为null//获取当前bean的class名
String className = mbd.getBeanClassName();
if (className != null) {
//对bean进行评估,(可将其解析为对应的表达式)返回其解析的value
Object evaluated = evaluateBeanDefinitionString(className, mbd);
//evaluated不是className时做处理
if (!className.equals(evaluated)) {
// A dynamically resolved expression, supported as of 4.2...
//是class类型
if (evaluated instanceof Class) {
return (Class>) evaluated;
}
//是String类型
else if (evaluated instanceof String) {
className = (String) evaluated;
freshResolve = true;
}
//都不是的话抛IllegalStateException异常
else {
throw new IllegalStateException("Invalid class name expression result: " + evaluated);
}
}
//className为null
if (freshResolve) {
// When resolving against a temporary class loader, exit early in order
// to avoid storing the resolved Class in the bean definition.
if (dynamicLoader != null) {
try {
//通过制定class名字去加载class
return dynamicLoader.loadClass(className);
}
catch (ClassNotFoundException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Could not load class [" + className + "] from " + dynamicLoader + ": " + ex);
}
}
}
//利用反射来构建class对象
return ClassUtils.forName(className, dynamicLoader);
}
}// Resolve regularly, caching the result in the BeanDefinition...
//定期解析,将结果保存到BeanDefinition中
return mbd.resolveBeanClass(beanClassLoader);
}
<3>. 在没有安全器时直接解析,解析的过程上面的方法中已经说明,主要是针对于String和class做了处理
- 处理override属性
不知道大家还记得之前有篇文章spring容器标签解析之lookup-method和文章spring容器标签解析之replaced-method中我们讲解了spring对lookup-method和replaced-method的解析过程,实际上是将解析中的配置保存到了BeanDefinition的methodOverrides属性中,这里也是同样的类似方法来处理,我们来看代码:
AbstractBeanDefinition.java
public void prepareMethodOverrides() throws BeanDefinitionValidationException {
// Check that lookup methods exists.if (hasMethodOverrides()) {
Set overrides = getMethodOverrides().getOverrides();
//同步枷锁
synchronized (overrides) {
//遍历执行prepareMethodOverride方法进行验证
for (MethodOverride mo : overrides) {
prepareMethodOverride(mo);
}
}
}
}
方法一看很明了,循环执行prepareMethodOverride方法进行处理,我们接着看:
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.
//进行对MethodOverride没有被覆盖,主要是为了避免参数类型检查的开始
mo.setOverloaded(false);
}
}
简单的来总结一下:
- 首先是获取方法名的个数
-如果count为0,直接抛BeanDefinitionValidationException异常 - 如果count为1时,设置没有被覆盖的方法
如果当前类只有一个方法,那么就设置重载该方法没有被重载,这样在后续调用的时候便可以直接使用找到的方法,而不需要进行方法的参数匹配验证了.
- 实例化的前置处理
我们可以看到的是在真正创建bean之前通过方法#resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd)来对BeanDefinition中的属性做些前置处理的操作,我们来看代码:
AbstractAutowireCapableBeanFactory.java
//3. 获取一个解析之后的代理bean的实例,而不是真正的bean实例
//给 BeanPostProcessors 一个机会用来返回一个代理类而不是真正的类实例
//AOP是基于此处实现的
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
上述代码中其实有一个很重要的判断,在我们调用#resolveBeforeInstantiation()后实际上返回的是一个代理对象,并非我们想要的真是对象,如果该代理对象不为null,那么它会直接略过后续的Bean的创建而是直接返回代理结果,很关键的一步,这也是AOP功能基于此处实现的,我们接着看获取代理对象的过程:
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
//如果尚未被解析
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
//获取目标的类型
Class> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
//<1>.前置
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
//<2>.后置
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
在上面的代码中,最重要的是<1>和<2>的处理过程,那关于如何处理的过程这里不再细究,后续来说.
- 创建bean的过程
当上面实例化前置处理时如果没有获取到对应的代理对象,那么这里就应该走正常的过程就是bean的创建过程,该过程是通过#doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) 方法来实现,我们来看代码:
/**
* 该方法是真正的创建bean的方法
* @param beanName 要创建bean的名称
* @param mbd 定义bean的beanDefinition文件
* @param args 创建bean时,构造方法所需的参数或者是调用bean工厂时来创建bean所需的参数
* @return 完成创建之后的bean的实例
* @throws BeanCreationException
*/
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {//实例化bean的过程
//BeanWrapper是对bean的包装,其接口中所定义的功能很简单包括设置获取被包装的对象,获取被包装 bean 的属性描述器
BeanWrapper instanceWrapper = null;
//1.如果是单例,从factoryBeanInstanceCache中移除相应的bean实例
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
//2.根据指定的bean使用对应的策略创建新的实例如:工厂方法、构造函数自动注入、简单初始化
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
//获取封装实例对象
final Object bean = instanceWrapper.getWrappedInstance();
//获取对应实例对象的类型
Class> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
//将获取到的bean类型赋值给mbd的resolvedTargetType
//resolvedTargetType用来保存真实类型bean的类型
mbd.resolvedTargetType = beanType;
}// Allow post-processors to modify the merged bean definition.
//3.允许后置处理修改mbd
synchronized (mbd.postProcessingLock) {
//postProcessed默认为false,故不能修改,这里取反表示可以修改
if (!mbd.postProcessed) {
try {
//后置处理修改beanDefinition
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}//4.对单例模式下的循环依赖进行检查
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//避免后期循环依赖,提早曝光创建的bean并加入到addSingletonFactory中
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}//初始化bean实例对象
Object exposedObject = bean;
try {
//5. 给bean的实例填充属性,其中,可能存在依赖于其他bean的属性,然后递归初始化bean的依赖
populateBean(beanName, mbd, instanceWrapper);
//6. 调用初始化方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
//7. 引用问题处理,这里先暴露早期单例引用的bean
if (earlySingletonExposure) {
//从缓存注册中获取,这里不允许早期引用的创建
Object earlySingletonReference = getSingleton(beanName, false);
//只有在检测到有依赖的情况下,earlySingletonReference才会不为null
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
//处理依赖
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}//8. 注册bean
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}return exposedObject;
}
简单的来总结下该方法:
- 在1处进行是否是单例的判断,如果是需要先清除缓存.
- 在2处调用#createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args)方法来实例化bean,于此同时将beanDefinition进行BeanWrapper的转换,其中BeanWrapper是对beanDefinition的包装,位于org.springframework.beans.BeanWrapper包中,详情后续来说.
- 在3处,MergedBeanDefinitionPostProcessor 的应用.
- 在4处,单例模式下的循环依赖处理.关于如何处理后面细说.
- 在5处,给bean进行属性的填充.如何填充后面来说.
- 在6处,调用 #initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) 方法,初始化 bean .详情见后面
- 在7处,循环依赖的检查和处理过程.
- 在8处,完成对DisDisposableBean的注册并返回
【spring容器之开启bean的创建之旅】关于创建的流程我们大致分了又以上8类,在后续的章节中我们分别来说.
推荐阅读
- Docker应用:容器间通信与Mariadb数据库主从复制
- PMSJ寻平面设计师之现代(Hyundai)
- 太平之莲
- 闲杂“细雨”
- 七年之痒之后
- 深入理解Go之generate
- 由浅入深理解AOP
- Activiti(一)SpringBoot2集成Activiti6
- 期刊|期刊 | 国内核心期刊之(北大核心)
- 生活随笔|好天气下的意外之喜