0104BeanDefinition合并和BeanClass加载-Bean生命周期详解-spring

1 前言

下面要介绍的阶段,都是在调用getBean()从容器中获取bean对象的过程中发生的操作,我们需要更多的去跟进源码。

在以后的讲解中,我们都采用API配置bean的方式,通过BeanDefinitionBuilder来完成bean的配置。

2 BeanDefinition合并

BeanDefinition合并核心方法

org.springframework.beans.factory.support.AbstractBeanFactory#getMergedBeanDefinition()

2.1 BeanDefinition合并在做什么?

不管我们在定义bean的时候,bean有没有父子关系。容器在注册初始BeanDefinition后,后续的相关操作都是在使用合并后的RootBeanDefinition。RootBeanDefinition会放入mergedBeanDefinitions中。

private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);
  • mergedBeanDefinitions:AbstractBeanFactory类中存放beanName-RootBeanDefinition键值对的map

定义了bean当然是为了使用,我们通过追踪下getBean()方法,看看是不是如上面我们所描述的一样是使用RootBeanDefinition而不是初始BeanDefinition。

factory.getBean()是调用AbstractBeanFactory中的方法,

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

继续调用doGetBean()方法,

protected <T> T doGetBean(
      String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
      throws BeansException {
   // 如果是别名,转换为最初的beanName
   String beanName = transformedBeanName(name);
   Object beanInstance;

   // Eagerly check singleton cache for manually registered singletons.
   Object sharedInstance = getSingleton(beanName);
   if (sharedInstance != null && args == null) {
     // 我们第一次获取bean容器中不会有bean实例
     // 省略...
   }

   else {
      // 省略...
      StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
            .tag("beanName", name);
      try {
         if (requiredType != null) {
            beanCreation.tag("beanType", requiredType::toString);
         }
          // 后续使用中使用的是合并后的RootBeanDefinition
         RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
        
		// 省略...
}

2.2 BeanDefinition怎么合并

我们通过源码来详细看看是如果合并的。在上面我们已经通过源码追踪到了执行合并的方法getMergedLocalBeanDefinition(),源码如下:

protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
   // Quick check on the concurrent map first, with minimal locking.
   RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
   if (mbd != null && !mbd.stale) {
       // 第一次获取,mergedBeanDefinitions并不会有beanName对应的RootBeanDefinition
      return mbd;
   }
   return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
  • getBeanDefinition(beanName)获取初始注册的BeanDefinition

继续调用getMergedBeanDefinition()

	protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
			throws BeanDefinitionStoreException {

		return getMergedBeanDefinition(beanName, bd, null);
	}

继续调用getMergedBeanDefinition()即合并BeanDefinition的主要方法

protected RootBeanDefinition getMergedBeanDefinition(
			String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
			throws BeanDefinitionStoreException {

		synchronized (this.mergedBeanDefinitions) {
			RootBeanDefinition mbd = null;
			RootBeanDefinition previous = null;

			// Check with full lock now in order to enforce the same merged instance.
			if (containingBd == null) {
				mbd = this.mergedBeanDefinitions.get(beanName);
			}

			if (mbd == null || mbd.stale) {
				previous = mbd;
				if (bd.getParentName() == null) {
                    // 父bean为空
					// Use copy of given root bean definition.
					if (bd instanceof RootBeanDefinition) {
                        // 原始的BeanDefinition为RootBeanDefinition,直接克隆
						mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
					}
					else {
                        // 原始的BeanDefinition不是RootBeanDefinition,new
						mbd = new RootBeanDefinition(bd);
					}
				}
				else {
                    // 父bean不为空,需要合并
					BeanDefinition pbd;
					try {
						String parentBeanName = transformedBeanName(bd.getParentName());
						if (!beanName.equals(parentBeanName)) {
                            // 默认beanName唯一,获取map中parentBeanName对应的RootBeanDefinition
							pbd = getMergedBeanDefinition(parentBeanName);
						}
						// 省略...
					// new,深拷贝
					mbd = new RootBeanDefinition(pbd);
                    // 子bean初始BeanDefinition的相关信息覆盖掉继承自RootBeanDefinition的相同信息
					mbd.overrideFrom(bd);
				}
			// 省略...
			return mbd;
		}
	}

合并逻辑如下:

  • 我们定义的bean没有父子关系时,合并bean其实就是新生成RootBeanDefinition对象,内容拷贝自初始BeanDefinition,并放入mergedBeanDefinitions集合;如果bean就是定义的RootBeanDefinition,直接拷贝。

  • 我们定义bean的有父子bean关系时,此时子BeanDefinition中的信息是不完整的,比如设置属性的时候配置在父BeanDefinition中,此时子BeanDefinition中是没有这些信息的。需要将子bean的BeanDefinition和从mergedBeanDefinitions集合获取的父bean对应的RootBeanDefinition进行合并,得到最终的一个RootBeanDefinition,合并之后得到的RootBeanDefinition包含bean定义的所有信息,包含了从父bean中继继承过来的所有信息,后续bean的所有创建工作就是依靠合并之后RootBeanDefinition来进行的。

  • 当定义的bean有多级父子关系,重复上述步骤;合并当前bean的初始BeanDefinition和从mergedBeanDefinitions 映射中获取父beanName对应的RootBeanDefinition。

2.3 示例演示

因为是做演示测试,没有通过factory.getBean()去debug调试,而是直接调用getMergedBeanDefinition()方法。

// User
package com.gaogzhen.myspring.bean;

/**
 * @author: Administrator
 * @version: 1.0
 * @createTime: 2023/02/20 07:49
 */
public class User {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}


// 测试方法
    public void testMergeAPI() {
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

        BeanDefinitionBuilder builder1 = BeanDefinitionBuilder.genericBeanDefinition(User.class)
                .addPropertyValue("name", "张三")
                .addPropertyValue("desc", "创立张氏制药厂");
        factory.registerBeanDefinition("user1", builder1.getBeanDefinition());

        BeanDefinitionBuilder builder2 = BeanDefinitionBuilder.genericBeanDefinition()
                .addPropertyValue("name", "张小三")
                .addPropertyValue("desc", "接管张氏制药厂")
                .addPropertyValue("manage", "开设分厂")
                .setParentName("user1");
        factory.registerBeanDefinition("user2", builder2.getBeanDefinition());


        BeanDefinitionBuilder builder3 = BeanDefinitionBuilder.genericBeanDefinition()
                .addPropertyValue("name", "张小小三")
                .addPropertyValue("operate", "成立张氏制药集团并上市")
                .setParentName("user2");
        factory.registerBeanDefinition("user3", builder3.getBeanDefinition());


        //遍历容器中注册的所有bean信息
        for (String beanName : factory.getBeanDefinitionNames()) {
            //通过bean名称获取原始的注册的BeanDefinition信息
            BeanDefinition beanDefinition = factory.getBeanDefinition(beanName);
            //获取合并之后的BeanDefinition信息
            BeanDefinition mergedBeanDefinition = factory.getMergedBeanDefinition(beanName);
            // 获取bean
            System.out.println(beanName);
            System.out.println("初始beanDefinition:" + beanDefinition);
            System.out.println("beanDefinition中的属性信息" + beanDefinition.getPropertyValues());
            System.out.println("-----------");
            System.out.println("合并之后mergedBeanDefinition:" + mergedBeanDefinition);
            System.out.println("mergedBeanDefinition中的属性信息" + mergedBeanDefinition.getPropertyValues());
            System.out.println("=================================");
        }

    }

打印输出:

user1
初始beanDefinition:Generic bean: class [com.gaogzhen.myspring.bean.User]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
beanDefinition中的属性信息PropertyValues: length=2; bean property 'name'; bean property 'desc'
-----------
合并之后mergedBeanDefinition:Root bean: class [com.gaogzhen.myspring.bean.User]; scope=singleton; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
mergedBeanDefinition中的属性信息PropertyValues: length=2; bean property 'name'; bean property 'desc'
=================================
user2
初始beanDefinition:Generic bean with parent 'user1': class [null]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
beanDefinition中的属性信息PropertyValues: length=3; bean property 'name'; bean property 'desc'; bean property 'manage'
-----------
合并之后mergedBeanDefinition:Root bean: class [com.gaogzhen.myspring.bean.User]; scope=singleton; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
mergedBeanDefinition中的属性信息PropertyValues: length=3; bean property 'name'; bean property 'desc'; bean property 'manage'
=================================
user3
初始beanDefinition:Generic bean with parent 'user2': class [null]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
beanDefinition中的属性信息PropertyValues: length=2; bean property 'name'; bean property 'operate'
-----------
合并之后mergedBeanDefinition:Root bean: class [com.gaogzhen.myspring.bean.User]; scope=singleton; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
mergedBeanDefinition中的属性信息PropertyValues: length=4; bean property 'name'; bean property 'desc'; bean property 'manage'; bean property 'operate'
=================================

Process finished with exit code 0

  • 从输出的结果中可以看到,合并之前,BeanDefinition是不完整的,比比如user2和user3中的class是null,属性信息也不完整,但是合并之后这些信息都完整了。

bean生命周期的后续阶段使用的是合并后的RootBeanDefinition。没有父bean的直接new RootBeanDefinition,属性拷贝自该bean的初始BeanDefinition;有父bean的,深拷贝父bean对应的RootBeanDefinition,然后用该bean的初始BeanDefinition覆盖相同属性。

3 Bean Class 加载

这个阶段就是将bean的class名称转换为Class类型的对象。

BeanDefinition中有个Object类型的字段:beanClass

private volatile Object beanClass;

用来表示bean的class对象,通常这个字段的值有2种类型,一种是bean对应的Class类型的对象,另一种是bean对应的Class的类名(或者类路径),第一种情况不需要解析,第二种情况:即这个字段是bean的类名的时候,就需要通过类加载器将其转换为一个Class对象。

此时会对阶段4中合并产生的RootBeanDefinition中的beanClass进行解析,将bean的类名转换为Class对象,然后赋值给beanClass字段。

源码位置:

org.springframework.beans.factory.support.AbstractBeanFactory#resolveBeanClass()

在BeanDefinition合并阶段,我们追踪到了AbstracBeanFactory的doGetbean方法,完成BeanDefinition合并,我们继续追踪,看下在哪里完成beanClass的加载?具体加载怎么做的?

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

   // 省略
         RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
         checkMergedBeanDefinition(mbd, beanName, args);

        // 省略
         // Create bean instance.
         if (mbd.isSingleton()) {
             // 我们通常bean scope都是单例的
            sharedInstance = getSingleton(beanName, () -> {
               try {
                  return createBean(beanName, mbd, args);
               }
               catch (BeansException ex) {
                  destroySingleton(beanName);
                  throw ex;
               }
            });
// 省略...
}

getSingleton()方法获取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) {
            // 省略...
         try {
            singletonObject = singletonFactory.getObject();
    // 省略
}

singletonObject初始为空,通过上一步传递的singletonFactory获取实例,即箭头函数里面return createBean(beanName, mbd, args),继续看下createBean()方法,继续调用AbstractAutowireCapableBeanFactory中的createBean()方法:

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {

   RootBeanDefinition mbdToUse = mbd;
	// 这里解析beanClass
   Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
// 省略..
}

继续调用AbstractBeanFactory中的resolveBeanClass()方法

@Nullable
protected Class<?> resolveBeanClass(RootBeanDefinition mbd, String beanName, Class<?>... typesToMatch)
      throws CannotLoadBeanClassException {

   try {
      if (mbd.hasBeanClass()) {
         return mbd.getBeanClass();
      }
      return doResolveBeanClass(mbd, typesToMatch);
// 省略异常处理
}
    
	public boolean hasBeanClass() {
		return (this.beanClass instanceof Class);
	}
  • 先判断RootBeanDefinition mbd中beanClass是否是Class类型,是直接返回
  • 不是说明是类路径字符串,调用doResolveBeanClass解析

查看doResolveBeanClass()方法

@Nullable
private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
      throws ClassNotFoundException {

   ClassLoader beanClassLoader = getBeanClassLoader();
   ClassLoader dynamicLoader = beanClassLoader;
   boolean freshResolve = false;

  // 省略...
   String className = mbd.getBeanClassName();
   if (className != null) {
      Object evaluated = evaluateBeanDefinitionString(className, mbd);
      if (!className.equals(evaluated)) {
     // 省略...
   }

   // Resolve regularly, caching the result in the BeanDefinition...
   return mbd.resolveBeanClass(beanClassLoader);
}
  • 如果指定了beanExpressionResolver,通过beanExpressionResolver解析,默认未指定

我们继续查找AbstracBeanDefinition 的resolveBeanClass方法

	@Nullable
	public Class<?> resolveBeanClass(@Nullable ClassLoader classLoader) throws ClassNotFoundException {
		String className = getBeanClassName();
		if (className == null) {
			return null;
		}
		Class<?> resolvedClass = ClassUtils.forName(className, classLoader);
		this.beanClass = resolvedClass;
		return resolvedClass;
	}

classUtils的forName()方法

public static Class<?> forName(String name, @Nullable ClassLoader classLoader)
      throws ClassNotFoundException, LinkageError {

   Assert.notNull(name, "Name must not be null");

   Class<?> clazz = resolvePrimitiveClassName(name);
   if (clazz == null) {
      clazz = commonClassCache.get(name);
   }
   if (clazz != null) {
      return clazz;
   }

   // 省略.. 非常规

   ClassLoader clToUse = classLoader;
   if (clToUse == null) {
      clToUse = getDefaultClassLoader();
   }
   try {
      return Class.forName(name, false, clToUse);
   }
  // 异常处理..
}
  • 通常我们配置的类路径形式:包名+类名字符串,通过Class.forName(name, false, clToUse)加载。

后记

❓QQ:806797785

⭐️源代码仓库地址:https://gitee.com/gaogzhen/spring6-study

参考:

[1]Spring系列之Bean生命周期详解[CP/OL].

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gaog2zh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值