spring5源码分析-bean的创建过程(一)

spring源码分析,到目前为止,这是第三篇了。

好了好了好了,终于可以开始写了,本文还是从一个案例进行分析源码。

public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		// getBean方法,获取一个bean,如果没有则会去创建
		System.out.println(applicationContext.getBean("userService"));
	}

还是老样子的案例,从getBean()方法下手,这个getBean方法里面就包含了创建bean的整个逻辑。

直接跳到核心doGetBean方法,之前在FactoryBean源码分析中,讲了如何一步一步跳到doGetBean方法,小编就不一一跟踪演示了,

为了方便讲解,小编把doGetBean方法,拆成几个段落给大家源码讲解。

第一段这就没什么好讲的了,在FactoryBean文章中,每一个方法的源码都有详细讲述过了。

	// 获取真正的beanName,什么叫做真正的beanName?
		// 假设小编创建一个bean叫做user,然后给它起了一个别名叫做,zhangshan
		// 这个时候小编如果用applicationContext.getBean("zhangshan") 来获取bean也是可以获取到的
		// 正是因为这个方法,它会通过zhangshan这个别名,来获取到user真正的beanName
        // 底层就是就是一个aliasMap,key = 别名(zhangshan) , value = 真正的beanName(user)
		final String beanName = transformedBeanName(name);
		Object bean;

		// 获取到真正的beanName之后,然后去spring单例池中有没有对应的bean对象
		// 在这个案例中,是可以获取到的。
		// 为什么能获取到呢? 因为小编在AppConfig中配置包的扫描路径,而且TestFactoryBean类上小编加了@Component注解,spring在启动的时候,当然会扫描到这个类。
		Object sharedInstance = getSingleton(beanName);  // Map<>
		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 + "'");
				}
			}
			// 判断sharedInstance是不是FactoryBean,如果是FactoryBean,那么真正需要拿到的是getObject方法所返回的对象
			// getObjectForBeanInstance这个方法就是核心了
			// 最后的返回结果,也是通过这个方法决定的
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

结合上面代码if条件来看,如果从getSingleton,单例池中获取的结果是null,那么接下来就会进入到else来创建一个bean。

首先来看到第一句代码,是一个if条件判断,判断什么呢? 判断当前需要创建的bean是否已经在创建中,在创建除开socpe是单例以外的bean,在创建前后都会有所保存记录,下面会详细介绍。如果当前bean没有再创建,则接着往下走,否则直接抛出异常信息。

在实际项目开发当中,当当使用spring一个框架肯定是不行的,可能还会整合springmvc、mybatis等等,这个时候就会产生父子容器。

当spring发现从当前容器中获取不到,在创建之前,会先去父BeanFactory中看看有没有。

else{
    	// 在创建原型bean的时候,记录一下当前bean在创建
			// 创建完成之后,会进行移除
			// 判断如果当前原型bean真正创建中,则直接抛出异常
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			// 父子容器
			// 如果spring当前容器找不到对应的bean,再获取到父BeanFactory
			// 看看父BeanFactory中有没有,没有再去创建
			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) {
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else if (requiredType != null) {
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
				else {
					return (T) parentBeanFactory.getBean(nameToLookup);
				}
			}
}

最后,当前BeanFactory中没有,也没有父BeanFactory,那么就需要自己去创建了。

那么创建一个bean,先需要获取到什么呢? 当然是合并后的beanDefinition ,不懂的小伙伴,去翻翻小编之前的文章,这里就不多介绍啦。spring5源码分析-BeanDefinition

获取到bd之后,接下来的代码就是检查是否有相互依赖的关系,我们来看下代码演示。

	// 得到合并后的BeanDefinition,之前介绍BeanDefinition的文章已经介绍过了,这里就不多讲了
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);

				// 检查是否有相互依赖
				// 加载DependsOn的bean
				String[] dependsOn = mbd.getDependsOn();
				if (dependsOn != null) {
					for (String dep : dependsOn) {
						// 判断beanName是不是也被dep依赖了,如果是,就是相互依赖
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						// 存在在两个map中
						registerDependentBean(dep, beanName);
						try {
							// 加载被依赖的bean
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}

使用@DependsOn注解来指定依赖关系,像下面代码就属于相互依赖的关系。

假设我们先创建的bean是userService,首先通过mbd.getDependsOn(); 来获取依赖关系,就会获取到userService依赖了orderService信息。

在创建userService的时候,依赖关系没有被记录,所以isDependent判断不会成立,接下来执行registerDependentBean(dep, beanName);这个方法,会记录相互的依赖关系。

既让userService依赖了orderService,那么当然也要创建orderService ,最后会调用getBean()来创建orderService,在创建orderService的时候,在isDependent判断就会成立,最后抛出BeanCreationException异常了。

@Component
@DependsOn("orderService")
public class UserService {
}


@Component
@DependsOn("userService")
public class OrderService {
}

public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		// getBean方法,获取一个bean,如果没有则会去创建
		System.out.println(applicationContext.getBean("userService"));
	}

警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userService' defined in file [/Volumes/Cute/Taify/学习/源码/spring/spring-framework/luban/out/production/classes/com/kk/service/UserService.class]: Circular depends-on relationship between 'userService' and 'orderService'

接下来这一部分,我们对检查相互依赖功能再进一步的源码分析,看看是如何检查相互依赖关系的。

主要的实现就是通过两个map,来分别记录依赖的类,和被依赖的类,来实现的这个功能。

    /**
	 *  记录依赖了哪些类 ,比如: userService 依赖类 orderService,key就是userService,set里面就是包含orderService
	 */
	private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);

	/**
	 *  记录被哪些类依赖了,比如:orderService 被 userService 依赖了,那key就是orderService,set里面就包含userService
	 */
	private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);
 
    /**
	 * 保存bean之间的依赖关系
     * 在创建userService时候,beanName = userService ,dependentBeanName = orderService
	 */
	public void registerDependentBean(String beanName, String dependentBeanName) {
		String canonicalName = canonicalName(beanName);

		// dependentBeanMap 表示当前bean依赖了哪些bean
		// 比如在创建的userService的时候,扫描到DependOn("orderService")
		// key = userService ,value = linkedHashSet{"orderService"}
		synchronized (this.dependentBeanMap) {
			Set<String> dependentBeans =
					this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
			if (!dependentBeans.add(dependentBeanName)) {
				return;
			}
		}

		// dependenciesForBeanMap 表达当前bean被谁依赖了
		// key = orderService ,value = linkedHashSet{"userService"}
		synchronized (this.dependenciesForBeanMap) {
			Set<String> dependenciesForBean =
					this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
			dependenciesForBean.add(canonicalName);
		}
	}

    // 外层先调用对这个方法
	protected boolean isDependent(String beanName, String dependentBeanName) {
		synchronized (this.dependentBeanMap) {
			return isDependent(beanName, dependentBeanName, null);
		}
	}


     /**
	 * 检查是否有相互依赖对关系
	 *
	 * @param beanName          假设 userService
	 * @param dependentBeanName 假设 orderService
	 * @param alreadySeen
	 * @return
	 */
	private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {
		if (alreadySeen != null && alreadySeen.contains(beanName)) {
			return false;
		}
		String canonicalName = canonicalName(beanName);
		// 获取当前创建对类依赖类哪些类 , 这里userService依赖类orderService,取出来对就是orderService
		Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
		if (dependentBeans == null) {
			return false;
		}
		// 然后判断是否包含了orderService,这一步就成立了
		if (dependentBeans.contains(dependentBeanName)) {
			return true;
		}
		for (String transitiveDependency : dependentBeans) {
			if (alreadySeen == null) {
				alreadySeen = new HashSet<>();
			}
			alreadySeen.add(beanName);
			if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
				return true;
			}
		}
		return false;
	}

如果子父容器都没有当前bean,并且也没有相互依赖的关系,接下来就是根据scope来进行创建bean了。

一共有3个分支,创建单例的、创建原型的、创建其他scope类型的。

先看创建原型和其他类型的,beforePrototypeCreation()、afterPrototypeCreation(),两个都有调用这两个方法,这两个方法就是记录当前bean正在创建中,和创建完成然后清除。实现的原理也很简单,就是通过一个ThreadLocal<Object> prototypesCurrentlyInCreation 来保存,创建之前set进去,创建完成之后remove掉。 源码比较简单,小编就不贴代码了。

重点看三个分支,全部都有调用createBean()方法,这个方法主要就是用来创建bean的,里面包含了初始化、属性填充、实例化等等一些逻辑,这个留在下一篇文章在讲述,不然文章内容太长了。

	// 根据Scope去创建bean
				if (mbd.isSingleton()) {
					// 获取单例bean,如果获取不到则创建一个bean,并且放入单例池中
					sharedInstance = getSingleton(beanName, () -> {
						try {
								return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							destroySingleton(beanName);
							throw ex;
						}
					});
					// sharedInstance可能是一个FactoryBean,所以需要单独再去factoryBeanObjectCache中去获取对应的对象
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
				else if (mbd.isPrototype()) {
					// 创建单例bean
					Object prototypeInstance = null;
					try {
						// 记录创建bean
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						// 清除创建bean记录
						afterPrototypeCreation(beanName);
					}
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}

				else {
					// 其他作用域的创建方式
					String scopeName = mbd.getScope(); // request, session
					final Scope scope = this.scopes.get(scopeName);
					if (scope == null) {
						throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
					}
					try {
						// 调用其他作用域的实现方式
						// 比如如果scope是request,创建出来的bean则会保存到request.setAttribute()当中
						Object scopedInstance = scope.get(beanName, () -> {

							// 记录创建
							beforePrototypeCreation(beanName);
							try {
								return createBean(beanName, mbd, args);
							}
							finally {
								// 清除创建bean记录
								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);
					}
				}

从上往下看,调用了getSingleton()方法,参数是beanName,和 一个lambda表示的createBean方法,

接下来看getSingleton的源码实现,主要的逻辑就是,先看单例池有没有,没有就创建,创建之前记录状态,然后调用创建的方法,移除记录,并且保存到单例池当中。

/**
	 * 获取单例bean,这个方法会调用创建bean,并且创建之后会保存到单例池当中
	 * @param beanName
	 * @param singletonFactory
	 * @return
	 */
	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);

			// 如果不存在实例,则创建单例bean实例
			if (singletonObject == null) {
				// 当前单例正在销毁中,则直接抛出异常
				if (this.singletonsCurrentlyInDestruction) {
					throw new BeanCreationNotAllowedException(beanName,
							"Singleton bean creation not allowed while singletons of this factory are in destruction " +
									"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
				}
				// 记录创建状态,把当前正在创建的beanName添加到singletonsCurrentlyInCreation中,singletonsCurrentlyInCreation是一个Set
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					// singletonFactory是外面传进来的lambda表达式,执行lambda表达式
					// 创建单例bean
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				} catch (IllegalStateException ex) {
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						throw ex;
					}
				} catch (BeanCreationException ex) {
					if (recordSuppressedExceptions) {
						for (Exception suppressedException : this.suppressedExceptions) {
							ex.addRelatedCause(suppressedException);
						}
					}
					throw ex;
				} finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
					// 移除状态,将刚刚正在创建的beanName从singletonsCurrentlyInCreation中移除
					afterSingletonCreation(beanName);
				}

				// 将创建好的单例bean添加到单例池singletonObjects中
				if (newSingleton) {
                    // 就是几个map的put、和remove,就不贴源码了
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

最后来讲讲其他scope类型的,通过源码可以看出,首先是从bd中获取了scope,然后scopes中,获取到了一个Scope对象。

那肯定就会有不同的实现类,通过scope属性来决定具体的实现实现类,最后调用get方法。

举个例子:比如现在scope=request,那么获取到的就是和reqeust相关的Scope实现类,最后这个bean对象会保存到request.setAttribute()当中。

剩下的逻辑就和其他的差不多了。

public interface Scope {


	Object get(String name, ObjectFactory<?> objectFactory);


	@Nullable
	Object remove(String name);


	void registerDestructionCallback(String name, Runnable callback);


	@Nullable
	Object resolveContextualObject(String key);


	@Nullable
	String getConversationId();

}

这篇文章看不看得懂就随缘啦,有问题可以提出来哟,下一篇文章会详细介绍createBean方法是如何创建bean的~~~~

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 终极编程指南 设计师:CSDN官方博客 返回首页
实付 29.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值