不断的学习,我们才能不断的前进
一个好的程序员是那种过单行线马路都要往两边看的人

Spring IOC

初始化IOC的流程:

  • prepareRefresh: 准备工作(记录容器的启动时间、标记状态等)-->
  • obtainFreshBeanFactory: 解析配置文件获取初始化的beanDefinition并存入到容器map里面--->
  • prepareBeanFactory: 设置BeanFactory的类加载器并注册一些特殊的bean(enviorment、systemProperties、systemEnvironment)--->
  • postProcessBeanFactory: 注册bean工厂后置处理器---->
  • invokeBeanFactoryPostProcessors: 激活并处理bean后置工厂处理器,可以访问并修改beanDefinition ---->
  • registerBeanPostProcessors: 向IOC容器注册bean后置处理器, 获取所有的BeanPostProcessors并存放到容器里面--->
  • 执行初始化(在初始化之前 和 初始化之后会执行bean后置处理器的逻辑)--->
  • 销毁bean

Spring 源码环境搭建过程?

Spring 源码搭建是从github上面gitclone下来,导入到idea即可,使用的是Gradle进行管理。

Spring 将配置文件解析成什么注册到容器的?

Spring 首先加载XML配置文件或者Java配置类,然后使用BeanDefinitionReader去处理配置信息,不同的配置有不同的实现类,比如:XML文件使用的是XMLBeanDefinitionReader的实现类,将配置解析成BeanDefinition接口的实现类,BeanDefinition里面包括class类型信息、Bean的生命周期(单例还是原型)、别名信息、是否懒加载等,解析成BeanDefinition后注入到容器里面,用于后面Bean的创建,这个容器里面key是beanName,value是对应的BeanDefinition对象。对于别名的话保存了别名到beanName的影视,相当于多了一次重定向。

BeanFactoryPostProcessor 可以做什么事情?

BeanFactoryPostProcessor 有一个接口方法postProcessBeanFactory,会传入当前容器的引用对象。在实例化Bean之前可以获取当前bean的定义也就是BeanDefinition,并可以修改它。

这部分可以用来扩展,只要自定义类实现 BeanFactoryPostProcessor 接口,并重写它的方法即可,然后注册这个Bean即可。在容器启动的时候会检查BeanDefinition的信息,然后将容器后置处理器接口的实现类通过反射进行实例化,然后执行接口方法。

BeanPostProcessor 和 BeanFactoryPostProcessor区别?

BeanFactoryPostProcessor是在Bean 实例化之前执行的,可以访问并修改Bean的定义。

BeanPostProcessor 是在实例化bean的过程中穿插执行的,用来增强Bean的功能。分割点在Initialization这个地方:

  • postProcessBeforeInitialization 在初始化之前执行;
  • postProcessAfterInitialization 在Bean初始化之后执行。

获取ApplicationContext实例需要实现ApplicationContextAware接口就是用来获取容器实例,就是Bean后处理器来完成的,在初始化之后,后置处理器会去检查实例对象是否实现了Aware接口,从而保存相应的信息。类似的@Autowire、@Value、Aop切面编程都需要BeanPostProcessor。

Spring 事件传播器的作用?监听者如何提供事件传播器?

Spring 事件传播器 在Spring生命周期内,接收相应事件并传播。

监听者只要实现Spring的监听者接口,并注册这个Bean即可。容器启动后会自动根据类型去获取BeanDefinition信息,实例化后注册到事件传播器里面。

预先实例化单实例的流程?

在容器加载解析完XML配置文件或者java配置类后,会转换成BeanDefinition对象并存放在容器里面的map里面,针对BeanDefinition 里面bean的生命周期有singleton,prototype、或者其他的值,默认是单例;针对单例类型bean,Spring 容器采用的是预先实例化的策略。也就是当容器启动后get获取到的Bean实例,都是从缓存里面获取到的,可以提升效率,但是对于配置懒加载的bean,它会在第一次get的时候去实例化。
实例化的过程
在获取到beanDefinition后,首先会转换成MergeBeanDefinition,目的是用来处理beanDefinition继承的,会创建一个新的对象mbd,把父beanDefinition信息拷贝到mbd,然后把当前的beanDefinition覆盖到mbd里面,就可以获取到包含父信息有又包含当前信息的beanDefinition。
接下来判断是否存在有依赖的Bean,有的话,先递归实例化依赖的Bean。
然后就根据beanDefinition中的class信息,和构造方法信息,找到合适的构造方法,通过反射进行实例化。

什么是循环依赖?

所谓循环依赖是指, 两个或者多个Bean相互之间持有对方引用,比如BeanA引用了BeanB,BeanB又引用了BeanC,BeanC引用BeanA这种。

在Spring中有构造器循环依赖sttter循环依赖、原型循环依赖,而只能解决通过setter方式且引用的Bean的作用域是Singleton级别

spring如何判定目前发生循环依赖的?

原型类型下的循环依赖
在原型模式下,使用的是ThreadLocal类型的set用来存储当前创建bean池, 实际上存储的是beanName。

private final ThreadLocal<Object> prototypesCurrentlyInCreation = new NamedThreadLocal<>("Prototype beans currently in creation");

** 单例构造器循环依赖 **
Spring 容器将每一个正在创建的bean 标识符放在一个“当前创建bean池,singletonsCurrentlyInCreation“, bean 标识符在创建过程中将一直保持在这个池中,因此如果在创建bean 过程中发现自己已经在“当前创建bean 池” 里时,将抛出BeanCurrentlylnCreationException 异常表示循环依赖;而对于创建完毕的bean 将从“ 当前创建bean 池”中清除掉。


/** 存储了当前正在创建的beanName */
private final Set<String> singletonsCurrentlyInCreation =
		Collections.newSetFromMap(new ConcurrentHashMap<>(16));

setter循环依赖
通过setter 注入方式构成的循环依赖。对于setter 注入造成的依赖是通过Spring 容器提前暴露刚完成构造器注入但未完成其他步骤(如setter 注入)的bean 来完成的,而且只能解决单例作用域的bean 循环依赖通过提前暴露一个单例工厂方法,从而使其他bean 能引用到该bean 。这样返回了Bean实例的引用,后期对bean的任何处理,不会改变bean的引用地址。
实际实现上提前暴露一个单例工厂方法,返回了一个在创建中的Bean,这样其他Bean就能够获得他的引用。

Spring setter注入依赖产生的循环依赖是怎么解决的?

通过三级缓存来解决的:

  • singletonObjects(一级缓存) :用于保存BeanName 和创建bean 实例之间的关系, bean name 一> bean Instance 。

  • singletonFactories(三级缓存) :用于保存BeanName 和创建bean 的工厂之间的关系, bean name 一> ObjectFactory ,一旦最终对象被创建(通过objectFactory.getObject()),此引用信息将删除

  • earlySingletonObjects(二级缓存) :也是保存BeanName 和创建bean 实例之间的关系,与singletonObjects 的不同之处在于,用于存储在创建Bean早期对创建的原始bean的一个引用,注意这里是原始bean,即使用工厂方法或构造方法创建出来的对象,一旦对象最终创建好,此引用信息将删除。其目的是用来检测循环引用

  • registeredSingletons :用来保存当前所有已注册的bean 。

解决方案

通过setter 注入方式构成的循环依赖。对于setter 注入造成的依赖是通过Spring 容器提前暴露刚完成构造器注入但未完成其他步骤(如setter 注入)的bean 来完成的
Demo: A 依赖B,B依赖C,C依赖A:具体步骤如下。

  1. Spring 容器创建单例“testA ” bean ,首先根据无参构造器创建bean,这个实例对象还没有进过初始化和后续的处理,还不可以使用,所以包装成一个“ObjectFactory”用于返回一个提前暴露一个创建中的bean,并存放到三级缓存里面 ,并将“testA”标识符放到“当前创建bean 池”, 然后进行setter 注入“testB ” 。

  2. 然后继续处理testA的早期实例对象,发现依赖对象B,然后会进行setter方式的依赖注入,通过getBean(B)获取B对象,但是发现B还没有实例化,所以就递归实例化B对象

  3. Spring 容器创建单例“ testB ” bean ,首先根据无参构造器创建bean ,所以包装成一个“ ObjectFactory”用于返回一个提前暴露一个创建中的bean ,并将“testB”标识符放到“当前创建bean 池”,然后进行setter 注入“testC ” 。

  4. Spring 容器创建单例“ testC ” bean ,首先根据无参构造器创建bean ,并暴露一个“ ObjectFactory”用于返回一个提前暴露一个创建中的bean ,并将“testC”标识符放到“当前创建bean 池”,然后进行setter 注入“testA” 。进行注入“testA”时由于提前暴了了“ObjectFactory”工厂,从而使用它返回提前暴露一个创建中的bean 。所以可以完成C依赖A的处理,完成C的实例化。C实例化之后,把C存放到Spring的一级缓存里面,并删除二级三级缓存里面的C对象。

  5. 最后在依赖注入“testB ”和“testA ”,完成setter 注入。

Spring 三级缓存的数据,什么时候升级到二级缓存?

三级缓存存放的是对象的bean工厂,通过getBean会拿到对象的三级缓存,也就是获取对象的ObjectFactory,然后通过ObjectFactory::get方法会拿到对象的早期实例,然后对象会进行缓存升级,从三级缓存升级到二级缓存,也就是删除三级缓存里面的beanName,放入到二级缓存里面。
当早期对象完成依赖注入,初始化一系列的处理后,会把对象存放到一级缓存,并删除二级缓存里面的内容。

Spring 为什么会出现三级缓存?

三级缓存是在初始化或者依赖注入之前 包装成ObjectFactory,并且存放到三级缓存里面
调用初始化方法时,会进行BeanPostProcess进行处理,也就是实现AOP功能,也就是动态代理,最后生成一个代理类,也就是新的class对象,新的class对象实例化之后包含原生对象,从而完成增强。在堆上的表现是新的代理对象和原生对象不再是一个地址空间,所以需要三级缓存存储原生对象的对象工厂。而且ObjectFactory::get方法做了一些处理,在返回早期实例之前,会执行一些BeanPostProcessor处理,会把AOP的BeanPostProcessor实现代理增强的逻辑进行预处理执行。
如果当前实例需要被增强,则ObjectFactory::get会返回增强后的实例,否则是原生实例对象。
三级缓存的目的也有为了解决循环依赖

单例bean解决循环依赖的流程图和源码分析

参考博客

singletonbean

在初始化bean的时候,会进行bean后置处理器的代码的执行: 执行顺序是:postProcessBeforeInitialization、 afterPropertiesSet、自定义初始化的方法、postProcessAfterInitialization。

源码分析

/** 一级缓存,单例缓存池,这里存储的bean是已经完成了实例化,属性注入,初始化等一系列操作的bean */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** 二级缓存:存储的提前暴露的早期对象,即只是调用了构造函数生成的bean对象 */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

/** 三级缓存:单例对象工厂缓存,存储了每个beanName所在的生产工厂,在调用构造生产实例时一般会加入到这里来 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
 
/** 当前正在创建对象集合:存储了当前正在创建的beanName */
private final Set<String> singletonsCurrentlyInCreation =
		Collections.newSetFromMap(new ConcurrentHashMap<>(16));
        
=========================大步骤1===================================

//真正实现向IOC容器获取Bean的功能,也是触发依赖注入功能的地方
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
		@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
        
     // 获取到真正的BeanName,因为有可能这个是别名
     String beanName = transformedBeanName(name);
     
	//从缓存里面获取beanName
	Object sharedInstance = getSingleton(beanName);
    
	// 缓存里面存在对象,创建单例模式Bean实例对象
	if (sharedInstance != null && args == null) {
		//获取给定Bean的实例对象,主要是完成FactoryBean的相关处理
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	} else {
        // 合并父类的BeanDefinition 
        RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
		checkMergedBeanDefinition(mbd, beanName, args);
        
		if (mbd.isSingleton()) {
			//这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
			sharedInstance = getSingleton(beanName, () -> {
				try {
					//创建一个指定Bean实例对象,如果有父级继承,则合并子类和父类的定义
					return createBean(beanName, mbd, args);
				}
				catch (BeansException ex) {
					//显式地从容器单例模式Bean缓存中清除实例对象
					destroySingleton(beanName);
					throw ex;
				}
			});
			//获取给定Bean的实例对象
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
		}
	}
	return (T) bean;
}

/**
 * 从缓存里面获取bean对象,,因为单例bean只创建一次
**/
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	//从单例bean池中获取,也就是一级缓存
	Object singletonObject = this.singletonObjects.get(beanName);
	//当前池中没有,并且当前bean正在创建当中,也就是存在循环依赖的时候
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		synchronized (this.singletonObjects) {
			//从二级缓存里面获取bean对象
			singletonObject = this.earlySingletonObjects.get(beanName);
			//早期bean为空,且运行提前引用
			if (singletonObject == null && allowEarlyReference) {
				//获取提前暴露的对象工厂,对象在通过构造函数创建生成实例后与生成对象的工厂建立绑定关系,便于后续解决循环依赖,也就是三级缓存
				ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
				//如果能提前获取到bean的对象工厂
				if (singletonFactory != null) {
					//可以从工厂的getObject方法中找到绑定的具体的bean,此时的bean暂未完成属性赋值
					singletonObject = singletonFactory.getObject();
					//缓存升级,提升到二级缓存
					this.earlySingletonObjects.put(beanName, singletonObject);
					this.singletonFactories.remove(beanName);
				}
			}
		}
	}
	return singletonObject;
}

// 判断当前正在创建集合中是否存在当前bean
public boolean isSingletonCurrentlyInCreation(String beanName) {
    //判断当前beanName是否正在创建当中
	return this.singletonsCurrentlyInCreation.contains(beanName);
}


=========================大步骤2===================================


/**
 * 从匿名内部类生成的对象工厂里面获取bean对象,会调用内部类的createBean方法
**/
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    //从单例缓存池中获取
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null) {
        ......
        //将当前的beanName加入正在创建的集合中
        beforeSingletonCreation(beanName);
        ......
        try {
            //从对象工厂中获取具体的实例,会调用doGetBean中的createBean
            singletonObject = singletonFactory.getObject();
            newSingleton = true;
        }catch (IllegalStateException ex) {
            ......
        }catch (BeanCreationException ex) {
            ......
        }
        finally {
            //从正在创建的bean集合中移除
            afterSingletonCreation(beanName);
        }
    
    }
}
 
//将beanName加入set集合中,表示当前bean正在创建
protected void beforeSingletonCreation(String beanName) {
	if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
		throw new BeanCurrentlyInCreationException(beanName);
	}
}
 
//将beanName从set集合中移除,表示当前bean已经创建完毕,加入到了单例缓存池中
protected void afterSingletonCreation(String beanName) {
	if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
		throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
	}
}

=========================大步骤3===================================

//doGetBean方法中的createBean方法,创建bean
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
		throws BeanCreationException {
	//创建Bean的入口
	Object beanInstance = doCreateBean(beanName, mbdToUse, args);

	return beanInstance;
}
 
//真正创建Bean的方法
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
		throws BeanCreationException {
	//...省略无关代码	
	
	//1.调用默认构造函数进行反射生成实例
	if (instanceWrapper == null) {
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	
	//向三级缓存容器中缓存早期单例模式的Bean对象,以防循环引用
	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
			isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
		//这里是一个匿名内部类,为了防止循环引用,尽早持有对象的引用
		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	}
	
	//2.Bean对象的初始化,依赖注入在此触发,发现循环依赖会去递归执行创建另外一个bean对象
	populateBean(beanName, mbd, instanceWrapper);
    
	//3.初始化Bean对象
	exposedObject = initializeBean(beanName, exposedObject, mbd);
	
	//...省略无关代码
	return exposedObject;
}

// 当前对象加入到三级缓存里面
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
	Assert.notNull(singletonFactory, "Singleton factory must not be null");
	synchronized (this.singletonObjects) {
		//单例缓存池中是否包含当前bean,此时还没有创建完成,肯定不包含
		if (!this.singletonObjects.containsKey(beanName)) {
			//将对象工程加入三级缓存
			this.singletonFactories.put(beanName, singletonFactory);
			//清空掉二级缓存
			this.earlySingletonObjects.remove(beanName);
			//将当前beanName加入到注册表中
			this.registeredSingletons.add(beanName);
		}
	}
}
 
//首先会通过当前方法来获取到singletonFactory
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
	Object exposedObject = bean;
	if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
				SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
				exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
			}
		}
	}
	return exposedObject;
}

参考文献

循环依赖的参考文献


目录