Spring之bean生命周期源码解析

 我的这篇文章是在系统学习Spring源码之后,基于自己对Spring源码的理解,来详细分析Spring之getBean()方法底层的实现。

一.Spring之getBean()方法常见的三种用法

1.getBean(String name),通过名字从Spring容器中获取bean,那么这个name可以是BeanFactory中bean真正的名字、也可以是在定义bean时指定的别名、还可以是带&符号的名字;

说明:如果一个bean是FactoryBean,那通过name获取到的bean是FactoryBean中getObject()方法返回的对象,想要获取到真正的FactoryBean对象,需要在name前面加&符号。

2.getBean(String name, Class<T> requiredType),通过名字和指定的类型从Spring容器中获取bean,参数requiredType相当于一个限定条件,如果根据name拿到的bean对象,不是requiredType类型并且不能进行类型转化,则会报错

<T> T adaptBeanInstance(String name, Object bean, @Nullable Class<?> requiredType) {
        //检查实际得到的bean实例与指定类型是否匹配
		if (requiredType != null && !requiredType.isInstance(bean)) {
			try {
			    //如果不匹配并且不能进行类型转换,则会抛异常
				Object convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
				if (convertedBean == null) {
					throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
				}
				return (T) 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;
	}

说明:此方法在AbstractBeanFactory中,位于doGetBean方法的最后,用于检查根据name获取到的bean对象是否与指定的requiredType适配。

3.getBean(String name, Object... args),Object... args与构造方法有关系,Spring创建对象默认会用无参的构造方法,如果name对应的bean是单例的并且是非懒加载的,那么Object... args是不会用到的,如果name对应的bean是原型的,并且bean所属的类里面有有参的构造方法,那么Spring在创建对象的时候就会将Object... args传给有参的构造方法,并且调用有参的构造方法创建对象。

 二、Spring之getBean()方法底层执行流程

1.解析调用getBean()方法时指定的name,还原成真正的beanName

Spring源码中真正执行获取bean的是doGetBean方法,因为在调用getBean()方法时,参数name会对应很多种情况(可能是beanName、也可能是别名、也能是加了&符号的名称),如果在用到name的时候才会做相应的处理,那么势必很多地方会有处理name的逻辑,同时也会造成大量的代码重复,所以Spring在doGetBean方法开始的地方就对各种情况的name做了统一的处理;

//处理各种情况的name
protected String transformedBeanName(String name) {
		return canonicalName(BeanFactoryUtils.transformedBeanName(name));
	}

 说明:BeanFactoryUtils.transformedBeanName(name)用来处理带&符号的名字,canonicalName(String name)用来处理别名的情况,最终transformedBeanName方法会把name还原成真正的beanName;

2.根据beanName从单例池获取bean实例,根据能否获取到bean实例,执行不同的分支处理逻辑

根据真正的beanName去单例池去获取,如果能获取到,那么此时会有两种情况:获取到的有可能是普通bean,也有可能是FactoryBean,所以还不能将获取到的bean直接返回,因为返回的bean实例有可能不是真正想要获取的bean,还需要根据name,beanName,以及从单例池中拿到的bean实例,去进一步判断想要获得的是FactoryBean还是普通bean,以下是判断的方法

protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
		if (BeanFactoryUtils.isFactoryDereference(name)) {
			if (beanInstance instanceof NullBean) {
				return beanInstance;
			}
			if (!(beanInstance instanceof FactoryBean)) {
				throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
			}
			if (mbd != null) {
				mbd.isFactoryBean = true;
			}
			return beanInstance;
		}

		if (!(beanInstance instanceof FactoryBean)) {
			return beanInstance;
		}
		Object object = null;
		if (mbd != null) {
			mbd.isFactoryBean = true;
		}
		else {
			// 从factoryBeanObjectCache中直接拿对象,factoryBeanObjectCache存的是getObject()方法返回的对象
			object = getCachedObjectForFactoryBean(beanName);
		}
		if (object == null) {
			// Return bean instance from factory.
			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
			// Caches object obtained from FactoryBean if it is a singleton.
			if (mbd == null && containsBeanDefinition(beanName)) {
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			// synthetic为true,表示这个Bean不是正常的一个Bean,可能只是起到辅助作用的,所以这种Bean就不用去执行PostProcessor了
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}

如果根据beanName从单例池中没有获取到bean实例,则会进入其它条件分支去判断,这里就要回顾下Spring的扫描,Spring在扫描的时候针对每一个符合条件的bean,都会生成一个相应的BeanDefinition,用于后续bean的创建;如果进入其它条件分支判断,首先看本容器里有没有beanName对应的BeanDefinition(通过beanDefinitionMap来检查),如果没有同时又有父BeanFactory,就调用父BeanFactory的getBean()方法来获取到bean实例,如果没有,则执行真正的创建bean的逻辑

	BeanFactory parentBeanFactory = getParentBeanFactory();
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				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);
				}
			}

3.执行真正的创建bean的逻辑,前提是步骤2中的条件均不满足

3.1.Spring在真正的创建bean之前,还会有一些准备及检查工作

  1)合并BeanDefination,Spring在定义bean的时候有可能会为当前bean对应的BeanDefination指定一个父BeanDefination

<bean id="mySchool" class="com.bj.study.School" scope="prototype abstract="true"/>
<bean id="myStudent" class="com.bj.study.Student" parent="mySchool"/>

  2) 检查BeanDefination是不是抽象的

  3) 检查有没有加 @DependsOn(),如果有,则需进一步检查会不会出现循环依赖

 3.2.根据BeanDefination的标识:单例、原型、还是其它作用域的bean,分别执行不同的逻辑去创建bean

StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
					.tag("beanName", name);
			try {
				if (requiredType != null) {
					beanCreation.tag("beanType", requiredType::toString);
				}
				//对BeanDefinition进行合并,会将child的属性与parent的属性进行合并,当有相同属性时,以 child 的为准
				RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

				// 检查BeanDefinition是不是Abstract的(抽象的BeanDefinition是不能创建bean的)
				checkMergedBeanDefinition(mbd, beanName, args);

				String[] dependsOn = mbd.getDependsOn();
				if (dependsOn != null) {
					// dependsOn表示当前所依赖的beanName,当前Bean创建之前dependsOn所依赖的Bean必须已经创建好了
					for (String dep : dependsOn) {
						// beanName是不是被dep依赖了,如果是则出现了循环依赖
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						// dep被beanName依赖了,存入dependentBeanMap中,dep为key,beanName为value
						registerDependentBean(dep, beanName);

						// 创建所依赖的bean
						try {
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}

				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							destroySingleton(beanName);
							throw ex;
						}
					});
					//不管创建的是单例bean、原型bean还是其它作用域的bean,都有可能创建出来的是一个FactoryBean,要再去调getObjectForBeanInstance()方法才能够得到真正的bean对象
					beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
				else if (mbd.isPrototype()) {
					Object prototypeInstance = null;
					try {
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
					beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}
				else {//实现其它的作用域的逻辑:例如SpringMVC中的request、session这些作用域
					//例如request,在同一个请求里面,根据同一个beanName拿到的bean对象应该是同一个,想要拿到的是同一个也得通过缓存来实现
					String scopeName = mbd.getScope();
					if (!StringUtils.hasLength(scopeName)) {
						throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
					}
					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);
							}
						});
						beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
					}
					catch (IllegalStateException ex) {
						throw new ScopeNotActiveException(beanName, scopeName, ex);
					}
				}
			}
			catch (BeansException ex) {
				beanCreation.tag("exception", ex.getClass().toString());
				beanCreation.tag("message", String.valueOf(ex.getMessage()));
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
			finally {
				beanCreation.end();
			}
		}

以下是关于创建bean的源码实现的链接

https://mp.csdn.net/mp_blog/creation/success/128409319

SpringBean生命周期源码主要涉及到Bean的初始化、依赖注入、后置处理、销毁等各个阶段。以下是一个简化的Spring Bean生命周期源码解析: 1. 实例化(Instantiation):Spring通过反射机制实例化Bean对象。这是通过调用构造函数或者工厂方法来完成的。 2. 属性注入(Property Injection):在实例化后,Spring将通过依赖注入(Dependency Injection)来设置Bean的属性值。这是通过调用setter方法或者直接访问字段来完成的。 3. Aware接口回调:Spring会检查Bean是否实现了某些Aware接口(如BeanNameAware、ApplicationContextAware等),并通过回调方法将相关的信息注入到Bean中。 4. BeanPostProcessor前置处理(BeanPostProcessor Pre-Initialization):Spring会检查是否有注册的BeanPostProcessor,如果有,则在Bean初始化前调用它们的postProcessBeforeInitialization方法。 5. 初始化(Initialization):初始化阶段包括两个步骤: a. 调用自定义的初始化方法(如通过@PostConstruct注解标记的方法或实现了InitializingBean接口的afterPropertiesSet方法)。 b. 调用BeanPostProcessor后置处理方法postProcessAfterInitialization。 6. 使用(In Use):此时Bean已经初始化完成,可以使用了。 7. 销毁(Destruction):在容器关闭或者手动销毁时,Spring会调用销毁方法来释放Bean占用的资源。 a. 调用自定义的销毁方法(如通过@PreDestroy注解标记的方法或实现了DisposableBean接口的destroy方法)。 b. 调用BeanPostProcessor后置处理方法postProcessBeforeDestruction。 以上是简化的Spring Bean生命周期源码解析,实际的源码会更加复杂和详细。Spring通过BeanPostProcessor和各种回调接口,提供了丰富的扩展点和生命周期管理功能,使开发者能够在Bean的不同阶段进行自定义操作。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值