spring IOC bean的加载流程

本文详细探讨了Spring IOC容器中Bean的加载过程,从getBean方法开始,逐步剖析doGetBean方法中的核心逻辑,包括处理BeanName、FactoryBean的处理等。通过时序图和代码分析,揭示了Bean的初始化、循环依赖解决等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

在前面的学习当中,我们了解了spring的资源加载策略,知道了spring如何将资源封装为Resource并且利用ResourceLoader加载Resource资源,然后解析Resource资源,将其装换为保存在spring内部的元数据BeanDefinition。前面做的所有工作都是在为IOC容器开始Bean的加载所做的准备。

在这里插入图片描述

IOC容器的作用如上图所示,它通过加载元数据,然后将其解析到容器内部。然后根据这些信息绑定整个系统的对象,最终 组装成一个可用的基于轻量级容器的应用系统。 要想真正得到一个完整的IOC容器,需要两步:1.容器的初始化阶段和bean的加载阶段,而现在我们学习的内容就是针对于第二个阶段。

在Bean的加载阶段开始的时候,加载Bean所需要的全部的信息已经进入到系统中了。当我们显式或者隐式地调用 BeanFactory#getBean(…) 方法的时候,就会开启Bean的加载过程。

实例代码如下:

		ResourceLoader resourceLoader = new DefaultResourceLoader();// <1>
		//ClassPathResource resource = new ClassPathResource("bean.xml");
		ClassPathResource resource = (ClassPathResource)resourceLoader.getResource("bean.xml");
		DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); // <2>
		XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); // <3>
		reader.loadBeanDefinitions(resource); // <4>

		Car car = (Car)factory.getBean("car");
		System.out.println(car);

为了便于梳理整个加载过程,其时序图如下:

在这里插入图片描述

这里的时序图只是bean加载过程当中我认为比较重要的方法,具体的看代码分析。

总体流程分析

getBean

当我们显式或者隐式掉一共getBean方法的时候,就会触发架子啊Bean阶段。

	@Override
	public Object getBean(String name) throws BeansException {
		//doGetBean接受4个方法参数:获取bean的名字,bean的类型
		//创建bean式要传递的参数,是否类型检查。
		return doGetBean(name, null, null, false);
	}

真正实现加载机制的是doGetBean方法

doGetBean

这个方法就是上面时序图的体现。代码如下:

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

		/**
		 * 通过name获取beanName,这里不使用name直接作为beanName有两个原因
		 * 1.name可能以&字符开头,表明调用者想获取FactoryBean本身,而不是FactoryBean实现类所创建的
		 * bean。在BeanFactory中,FactoryBean的实现类和其他的bean存储方式是一样的。区别在于名字上多了个&
		 * 所以要移除这个&
		 * 2.还是别名的问题,转换需要。
		 */
		//1.返回bean名称,剥离工厂使用前缀,如果那么是alias,就过去对应的映射的beanname
		//如果是FactoryBean,要去除它前面的那个&
		final String beanName = transformedBeanName(name);
		//创建一个空的bean
		Object bean;
		// Eagerly check singleton cache for manually registered singletons.
		//如果这里是我们的bean,那么第一次获取肯定是空的,那么这个时候就会走else
		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 + "'");
				}
			}
			//2.完成FactoryBean的相关处理,并用来获取FactoryBean的处理结果。
			//缓存中的bean记录的是最原始的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.
			//3.因为spring只支持解决单例模式下的循环依赖,所以原型模式下会抛出异常。
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}
			// Check if bean definition exists in this factory.
			//4.如果容器中没有找到就从父类容器中加载
			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 {
					// No args -> delegate to standard getBean method.
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
			}
			//5.如果不是仅仅做类型检查则是创建bean,这里需要记录
			if (!typeCheckOnly) {
				markBeanAsCreated(beanName);
			}

			try {
				//6.从容器中获取beanname对应的 GenericBeanDefinition 对象,
				// 并将其转换为 RootBeanDefinition 对象,转换的原因是RootBeanDefinition是子类
				//它提供了更多的方法供之后使用
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				//检查给定的合并的BeanDefinition
				checkMergedBeanDefinition(mbd, beanName, args);

				// Guarantee initialization of beans that the current bean depends on.
				String[] dependsOn = mbd.getDependsOn();
				//7.处理所依赖的bean
				if (dependsOn != null) {
					for (String dep : dependsOn) {
						//若给定的依赖bean已经注册为依赖给定的bean
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						//缓存依赖调用.......
						registerDependentBean(dep, beanName);
						try {
							//递归处理依赖bean
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}
				//8.bean实例化
				// Create bean instance.
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							//这里才开始正式创建
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							//显式从单例池中删除Bean实例
							//因为单例模式下为了解决循环依赖,可能它已经存在了.....
							// 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);
				}
				//原型模式下创建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);
				}

				else {
					//从指定的scope下创建bean
					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;
			}
		}
		//9.检查需要的类型是否符合bean的实际类型
		// 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.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;
	}

在这个代码中IOC完成了Bean的加载。同时循环依赖的解决也是在这个代码中完成的。由于这个代码很长,可以根据执行的顺序一步一步学习。

  • 首先处理Beanname,这个name的处理主要解决两个问题,1.将FactoryBean的名字的前缀去掉2.将别名改为真正的名字
  • 然后第一次通过getSingleton从单例池或者缓存中获取实例。缓存是解决循环依赖使用的,之后会讲。如果获取到了调用getObjectForBeanInstance进行FactoryBean的处理。
  • 大部分的代码如上所示,之后的学习中主要围绕这个代码学习

处理Beanname

transformedBeanName这个方法是doGetBean方法中最开始需要执行的逻辑

// AbstractBeanFactory.java

final String beanName = transformedBeanName(name);

protected String transformedBeanName(String name) {
    //canonicalName取指定的alias所比表示的最终的beanname
    return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}

public static String transformedBeanName(String name) {
    Assert.notNull(name, "'name' must not be null");
    String beanName = name;
    while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
        beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
    }
    return beanName;
}
//SimpleAliasRegistry.java
public String canonicalName(String name) {
    String canonicalName = name;
    // Handle aliasing...
    String resolvedName;
    do {
        //到记录别名的map中去一个一个比较。
        resolvedName = this.aliasMap.get(canonicalName);
        if (resolvedName != null) {
            canonicalName = resolvedName;
        }
    }
    while (resolvedName != null);
    return canonicalName;
}
  • transformedBeanName的主要作用是去除name的修饰符,name可能以&字符开头,表明调用者想获取FactoryBean本身,而不是FactoryBean实现类所创建的 bean。在BeanFactory中,FactoryBean的实现类和其他的bean存储方式是一样的。区别在于名字上多了个&
  • canonicalName进行别名的转换

总而言之,在transformedBeanName方法中对传入的name进行了处理,方便下面进行操作。

FactoryBean简介

我觉得这个知识点值得单独学习,所以这里就是简单概括一下。

一般来说spring利用反射机制来注入我们配置的bean的属性。但是如果我们在配置bean的时候,有很多的配置项,那么利用反射来注入就会比较复杂。所以Spring提供了 org.Springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化bean的逻辑。

package org.Springframework.beans.factory; public interface FactoryBean<T> {    
   T getObject() throws Exception;    
   Class<?> getObjectType(); boolean isSingleton();    
} 

比如一个实例:

public class CarFactoryBean implements FactoryBean<Car> { 
     private String carInfo; 
     public Car getObject() throws Exception {
        Car car = new Car();
        String[] infos = carInfo.split(",");
        car.setBrand(infos[0]);
        car.setMaxSpeed(Integer.valueOf(infos[1]));
        car.setPrice(Double.valueOf(infos[2])); return car;
    }
    public Class<Car> getObjectType() { 
      return Car.class;
    }
    public boolean isSingleton() {
      return false;
   } 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值