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的~~~~