这可能是全网分析bean加载流程最详细的文章了,希望对你有所帮助
上一篇文章分析了spring读取配置文件的源码,看过之后我相信你对配置文件的加载流程应该有了大概的了解,因为配置文件的解析代码并不复杂,只不过对我们来说比较生疏,因为xml解析平时开发不怎么用,我们没必要了解的太过深入,因为那并不是我们要了解的重点,真正的重点就从现在开始,那就是bean的加载。今天要分析的代码是测试类的第17行,不知道第17行的,看下上篇文章spring配置文件的解析
MyTestBean myTestBean = (MyTestBean)beanFactory.getBean("myTestBean");
这行代码在你刚接触spring的时候应该写过,当时自己写个单测,获取下bean,然后调下bean的方法,但是实际开发中并不常见,实际开发时都是用的注解比如@Resource,@Autowired直接将需要的bean进行注入,是不是你用注解了就不会用上面的getBean方法了?并不是,你用注解的话还是会调用getBean方法的,只不过是spring框架帮你调了,你只要记住,去spring容器中获取bean,必须通过getBean方法,这是唯一的入口,而BeanFactory就是spring容器的抽象,所有的容器要么是BeanFactory的子类的实现要么就是BeanFactory本身的实现。
接下来就开始分析bean的加载流程,其实上面的代码你按ctrl点击去,就会发现核心的方法叫doGetBean,这个方法就是bean加载的核心方法,咱先对这个方法中的关键代码做一个解释,然后再分析每个方法,不然如果像上篇那样一步步debug的话会有点蒙,先看下这个方法:
protected T doGetBean(final String name, @Nullable final Class requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
/**别名转换:你传进来的name有可能是个别名, 需要通过这个方法转换成真正的bean名称 */ final String beanName = transformedBeanName(name); Object bean; //从三级缓存中获取bean Object sharedInstance = getSingleton(beanName); //一、如果从缓存中获取到了,就直接拿来用就行了,不用再重复创建 if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
/**这里判断下这个bean是否正在被创建, 如果正在被创建而且还在缓存中的话, 证明现在出现了循环依赖,为什么? 先说下什么是循环依赖:A中有个B属性,B中也有A属性, 创建A的时候发现属性B,( 这时候isSingletonCurrentlyInCreation肯定是有A的, 因为刚才说了,只有在A创建的前置处理中才把A加到了 isSingletonCurrentlyInCreation这个集合里) 于是去创建属性B,然后发现B中也有A,于是又去创建A,可此时 A正在创建了,所以这就出现了循环依赖 */ //出现了循环依赖,返回了半成品的bean,因为循环依赖中 //被依赖的Bean必须等待依赖的Bean创建完成后才能继续创建 logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); }else {
//如果不是循环依赖的话,打印从缓存中获取到了实例bean logger.debug("Returning cached instance of singleton bean '" + beanName + "'"); } } /** 这里的getObjectForBeanInstance方法完成的是FactoryBean的相关处理,它会根据我们传入的sharedInstance操作 如果sharedInstance不是FactoryBean的话,就直接返回我们传进来的sharedInstance; 如果是的话,就利用我们传进来的FactoryBean(也就是sharedInstance)来生成我们索要的Bean */ bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); }else {
//二、如果从缓存中没有获取到 /**判断是否是多例模式创建中,是的话抛出异常,多例bean创建也得按顺序 创建完一个才能创建第二个,因为创建对象的过程并不是线程安全的*/ if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName); } //获取父类工厂 BeanFactory parentBeanFactory = getParentBeanFactory(); /** 如果 beanDefinitionMap 中不存在 beanName 的 BeanDefinition (记得上一篇文章最后一个图吗,加载配置后,bean是存到了一个名叫 beanDefinitionMap的map里)并且父类工厂不为空,则尝试从 parentBeanFactory 中加载,还是走的这个getBean方法, 不过是父类工厂进行调用。 */ if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
/**这一步是转换bean名字,点进去看这句代码做了两步: 1:别名转换,注意这里传进来的是name,不是beanName,name有可能是别名 2:然后判断如果是以&开头的,就把&拼到beanName的前面 */ String nameToLookup = originalBeanName(name); //然后判断父类工厂是不是AbstractBeanFactory类型的 if (parentBeanFactory instanceof AbstractBeanFactory) {
//如果是,继续调用AbstractBeanFactory的doGetBean方法 return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup, requiredType, args, typeCheckOnly); }else if (args != null) {
/**判断如果传进来的参数不为空,再调的时候就把参数传进来, BeanFactory的getBean方法是个重载方法,可以看下 */ return (T) parentBeanFactory.getBean(nameToLookup, args); }else {
/** 否则就只能走这个分支了,requiredType这个参数说下, 对getBean调用的时候requiredType是空的,但是可能会存在这种情况: 返回的bean其实是个String,但是requiredType却传入的是Integer, 这时候这个步骤就起作用了,所以它的功能就是将返回的bean转换成 requiredType所指定的类型 */ return parentBeanFactory.getBean(nameToLookup, requiredType); } } if (!typeCheckOnly) {
/**这个方法里涉及到两个集合: 1:alreadyCreated:这是一个set,存放已经被创建成功的bean的名称 这里面的bean至少被创建过一次 2:mergedBeanDefinitions:BeanDefinition里面包含了一个类的所有 信息,父类工厂里也会有BeanDefinition,那么子类工厂中的BeanDefinition 父类工厂中的BeanDefinition合并后就得到了RootBeanDefinition。 这个方法中判断了如果alreadyCreated这个集合里不存在这个bean的话, 就清空mergedBeanDefinitions。 */ markBeanAsCreated(beanName); } try {
/**这一步就是合并父类工厂和子类工厂中的BeanDefinition 生成一个RootBeanDefinition,因为后续的操作都是基于 BeanDefinition的,所以这是必须要转的 */ final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); //这一步就是检查这个bean是不是抽象的,抽象的话就抛异常了,因为抽象bean是不能被实例化的 checkMergedBeanDefinition(mbd, beanName, args); //获取依赖的bean String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) {
//循环 for (String dep : dependsOn) {
//判断beanName是否被dep依赖 if (isDependent(beanName, dep)) {
/**如果beanName所依赖的dependsOnBean, 已经存在于beanName的依赖列表里,就报错 (对于这里个人的理解是:doGetBean这个方法不是加锁的,可以 有多个线程同时操作,这里抛出异常是为了防止当前线程调用doGetBean 还没结束,其他线程再次调用doGetBean从而造成线程安全问题。)*/ throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); } //将依赖关系添加到两个map中,一个map表示依赖,一个map表示被依赖 registerDependentBean(dep, beanName); try {
//获取依赖的bean,其实又去调getBean方法了,因为要生成依赖的bean getBean(dep); }catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", ex); } } } //判断是bean是否是单例的,其实是判断bean的scope,spring默认是singleton,也就是单例的 if (mbd.isSingleton()) {
//创建单例bean sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args); } catch (BeansException ex) {
throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }else if (mbd.isPrototype()) {
//如果是原生模式(多例) Object prototypeInstance = null; try {
/**往prototypesCurrentlyInCreation 添加beanName标识着当前正在创建这个bean (注意这里spring用了一个threadlocal,妙啊) */ beforePrototypeCreation(beanName); //创建bean prototypeInstance = createBean(beanName, m