1. Spring Framework架构图
后面主要涉及到Beans、Context、AOP、Transactions、MVC等方面的内容。
2. Beans
2.1 BeanFactory的初始化
2.1.1 加载配置文件
- 在Spring中,资源文件被统一封装成Resource对象, 资源处理可以用Resource提供的各种服务来进行操作。
- 如:
Resource classPathResource = new ClassPathResource("beanFactoryTest.xml");
- 对不同来源的资源文件都有相应的Resource实现:文件(FileSystemResource)、Classpath资源(ClassPathResource)、URL资源(UrlResource)、InputStream资源(InputStreamResource)、Byte数组(ByteArrayResource)等。
- 有了Resource接口便可以对所有资源文件进行统一处理。至于实现,其实是非常简单的,以getInputStream为例,ClassPathResource中的实现方式便是通过class或者classLoader提供的底层方法进行调用,而对于FileSystemResource的实现其实更简单,直接使用FileInputStream对文件进行实例化。
2.1.2 创建BeanFactory
创建BeanFactory就更简单了,有时直接new一个出来。
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
2.1.3 加载BeanDefinitions
- BeanDefinition是配置文件<bean>元素标签在容器中的内部表示形式,主要封装了每个Bean的相关信息。Spring通过BeanDefinition将配置文件中的<bean>配置信息转换为容器的内部表示,并将这些BeanDefinition注册到BeanDefinitionRegistry中。Spring容器的BeanDefinitionRegistry就像是Spring容器配置信息的内存数据库,主要以map的形式保存,后续操作直接从BeanDefinitionRegistry中读取配置信息。
- 以XmlBeanFactory为例,真正加载BeanDefinition的函数 doLoadBeanDefinitions()主要做了两件事情:
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
- 利用之前配置文件封装好的Resource对象加载XML文件,并得到对应的Document;
- 根据返回的Document注册Bean信息:doRegisterBeanDefinitions( );
a. 获取Document的root节点,递归变量Document中的每一个节点;
b. 解析每一个节点,注册BeanDefinition(在后续bean的加载中会用到);
i. parseBeanDefinitions中会解析xml文件的各种标签,如<import>,<bean>,而<beans>该标签又会递归调用doRegisterBeanDefinitions。
// public static final String BEAN_ELEMENT = "bean";
public static final String BEAN_ELEMENT = BeanDefinitionParserDelegate.BEAN_ELEMENT;
public static final String NESTED_BEANS_ELEMENT = "beans";
public static final String ALIAS_ELEMENT = "alias";
public static final String IMPORT_ELEMENT = "import";
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
ii. 解析xml的各项标签完成后,还需要注册BeanDefinition(如processBeanDefinition()方法),包括通过beanName注册和通过别名alias注册(如果对某个bean配置了一个或多个别名,还需要将别名注册):
* 注册BeanDefinition就是将BeanDefinition放入map(BeanDefinitionMap,concurrentHashMap)中,key为beanName,value为BeanDefinition;
* this.beanDefinitionMap.put(beanName, beanDefinition);
* 通过alias注册(processAliasRegistration()方法): 将alias放入map(aliasMap,concurrentHashMap)中,key为alias,value为beanName;
iii. 当每个bean被解析并注册完成后,会发出响应事件(fireComponentRegistered),通知相关的监听器。这里的实现只是为了扩展,当开发者需要对注册BeanDefinition事件进行监听时,可以通过注册监听器的方式并将处理逻辑写入监听器中,目前在spring中并没有对此事件做任何逻辑处理。
这些步骤其实也都是包含在ApplicationContext的初始化中哦,也就是ApplicationContext几乎包含BeanFactory的所有功能。
2.2 Bean的加载
加载Bean的开始,BeanFactory#getBean(String beanName)。
对于加载过程中所涉及的步骤大致如下:
- 转换对应beanName。
- 或许很多人不理解转换对应beanName是什么意思,传入的参数name不就是beanName吗?其实不是,这里传入的参数可能是别名,也可能是FactoryBean,所以需要进行一系列的解析,这些解析内容包括如下内容。
a. 去除FactoryBean的修饰符,也就是如果name="&aa",那么会首先去除&而使name="aa"。
b. 指定alias所表示的最终beanName,例如别名A指向名称为B的bean则返回B;若别名A指向别名B,别名B又指向名称为C的bean则返回C。
- 尝试从缓存中加载单例。
- 单例在Spring的同一个容器内只会被创建一次,后续再获取bean,就直接从单例缓存中获取了。当然这里也只是尝试加载,首先尝试从缓存中加载,如果加载不成功则再次尝试从singletonFactories中加载。因为在创建单例bean的时候会存在依赖注入的情况,
而在创建依赖的时候为了避免循环依赖,在Spring中创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光加入到缓存中,一旦下一个bean创建时候需要依赖上一个bean则直接使用ObjectFactory(后面还会说明)。
- bean的实例化。
- 如果从缓存中得到了bean的原始状态,则需要对bean进行实例化。这里有必要强调一下,缓存中记录的只是最原始的bean状态,并不一定是我们最终想要的bean。举个例子,假如我们需要对工厂bean进行处理,那么这里得到的其实是工厂bean的初始状态,但是我们真正需要的是工厂bean中定义的factory-method方法中返回的bean,而getObjectForBeanInstance就是完成这个工作的。
- 原型模式的依赖检查。
- 只有在单例情况下才会尝试解决循环依赖,如果存在A中有B的属性,B中有A的属性,那么当依赖注入的时候,就会产生当A还未创建完的时候因为对于B的创建再次返回创建A,造成循环依赖,也就是情况:isPrototypeCurrentlyInCreation(beanName)判断true。
- 检测parentBeanFactory。
- 从代码上看,如果缓存没有数据的话直接转到父类工厂上去加载了,这是为什么呢?
- 可能读者忽略了一个很重要的判断条件:parentBeanFactory != null && !containsBeanDefinition (beanName),parentBeanFactory != null。parentBeanFactory如果为空,则其他一切都是浮云,这个没什么说的,但是!containsBeanDefinition(beanName)就比较重要了,它是在检测如果当前加载的XML配置文件中不包含beanName所对应的配置,就只能到parentBeanFactory去尝试下了,然后再去递归的调用getBean方法。
- 将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition。
- 因为从XML配置文件中读取到的Bean信息是存储在GernericBeanDefinition中的,但是所有的Bean后续处理都是针对于RootBeanDefinition的,所以这里需要进行一个转换,转换的同时如果父类bean不为空的话,则会一并合并父类的属性。
- 寻找依赖。
- 因为bean的初始化过程中很可能会用到某些属性,而某些属性很可能是动态配置的,并且配置成依赖于其他的bean,那么这个时候就有必要先加载依赖的bean,所以,在Spring的加载顺寻中,在初始化某一个bean的时候首先会初始化这个bean所对应的依赖。
- 针对不同的scope进行bean的创建。
- 我们都知道,在Spring中存在着不同的scope,其中默认的是singleton,但是还有些其他的配置诸如prototype、request之类的。在这个步骤中,Spring会根据不同的配置进行不同的初始化策略。
createBean():
* 利用反射创建Bean,BeanUtils.instantiateClass(constructorToUse),如果有动态代理则创建
* 属性注入populateBean()方法注入属性,循环查找Bean所需注入的属性(分为autowiredByName和autowiredByType),使用getBean()方法获取并注入
* 调用initializeBean方法完成用户自定义的初始化方法,该方法会先调用postProcessBeforeInitialization再调用InitializingBean.afterPropertiesSet(需要实现InitializingBean接口,实现用户自定义afterPropertiesSet方法)再调用postProcessAfterInitialization
- 类型转换。
- 程序到这里返回bean后已经基本结束了,通常对该方法的调用参数requiredType是为空的,但是可能会存在这样的情况,返回的bean其实是个String,但是requiredType却传入Integer类型,那么这时候本步骤就会起作用了,它的功能是将返回的bean转换为requiredType所指定的类型。当然,String转换为Integer是最简单的一种转换,在Spring中提供了各种各样的转换器,用户也可以自己扩展转换器来满足需求。
以AbstractBeanFactory为例:
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
/**
* 1. 转换BeanName
*/
final String beanName = transformedBeanName(name);
Object bean;
/**
* 2. 尝试从缓存中加载单例
* 首先尝试从缓存中加载,如果加载不成功则再次尝试从singletonFactories中加载。
* 因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,
* 在Spring中创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光加入到缓存中,
* 一旦下一个bean创建时候需要依赖上一个bean则直接使用ObjectFactory
*/
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
/**
* 3. Bean的实例化
* 判断得到的Bean是否为FactoryBean,如果是则从FactoryBean中获取bean实例(FactoryBean#getObject())
*
*/
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
/**
* 2.1 如果缓存中没有
*/
else {
/**
* 4. 原型模式的依赖检查,如果原型模式有循环依赖则抛出异常
*/
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
/**
* 5. 当父工厂不为空,且BeanDefinition在父工厂中,则从父工厂中获取Bean
*/
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
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 {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
/**
* 6. 转换得到RootBeanDefinition
* 在Spring中可以定义父子Bean,子类Bean可以继承父类Bean的属性,这里就是"递归向上"合并父子Bean的属性
*/
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
/**
* 7. 寻找Bean的依赖
*/
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
/**
* 7.1 实例化所有依赖Bean
*/
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
/**
* 8. 根据不同的scope创建Bean
*/
if (mbd.isSingleton()) {
/**
* 8.1 创建Bean,并加入缓存
*/
sharedInstance = getSingleton(beanName, () -> {
try {
/**
* 8.2 创建Bean
* 利用反射创建Bean,BeanUtils.instantiateClass(constructorToUse),如果有动态代理则创建
* 属性注入populateBean(),循环查找Bean所需注入的属性(分为autowiredByName和autowiredByType),使用getBean()方法获取并注入
* 调用initializeBean方法完成用户自定义的初始化方法,该方法会先调用postProcessBeforeInitialization再调用InitializingBean.afterPropertiesSet(需要实现InitializingBean接口,实现用户自定义afterPropertiesSet方法)再调用postProcessAfterInitialization
*/
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
/**
* 8.2 Bean的实例化
*/
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final 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);
}
});
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);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
/**
* 9. 类型转换
*/
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
2.2.1 FactoryBean
一般情况下,Spring通过反射机制利用bean的class属性指定实现类来实例化bean 。在某些情况下,实例化bean过程比较复杂,如果按照传统的方式,则需要在<bean>中提供大量的配置信息,配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.Springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化bean的逻辑。
FactoryBean接口对于Spring框架来说占有重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂bean的细节,给上层应用带来了便利。
也就是说通过getBean()方法返回的不是FactoryBean本身,而是FactoryBean#getObject()方法所返回的对象,相当于FactoryBean#getObject()代理了getBean()方法。
2.3 解决循环依赖
循环依赖的产生可能有很多种情况,例如:
- A的构造方法中依赖了B的实例对象,同时B的构造方法中依赖了A的实例对象;
- A的构造方法中依赖了B的实例对象,同时B的某个field或者setter需要A的实例对象;
- A的某个field或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象;
当然,Spring对于循环依赖的解决不是无条件的,首先前提条件是针对scope单例并且没有显式指明不需要解决循环依赖的对象,而且要求该对象没有被代理过。同时Spring解决循环依赖也不是万能,以上三种情况只能解决两种,第一种在构造方法中相互依赖的情况Spring也无法解决。
而第二种情况下,需要保证先初始化B,可以使用@DependsOn
2.3.1 单例模式(Singleton)的循环依赖
Spring循环依赖的理论依据其实是Java基于引用传递,当我们获取到对象的引用时,对象的field或者或属性是可以延后设置的。
Spring单例对象的初始化其实可以分为三步(就是上文中的createBean()方法):
- createBeanInstance, 实例化,实际上就是调用对应的构造方法构造对象,此时只是调用了构造方法,spring xml中指定的property并没有进行populate
- populateBean,填充属性,这步对spring xml中指定的property进行populate;
- initializeBean,调用spring xml中指定的init方法,或者AfterPropertiesSet方法 ;
会发生循环依赖的步骤集中在第一步和第二步。
三级缓存
对于单例对象来说,在Spring的整个容器的生命周期内,有且只存在一个对象,很容易想到这个对象应该存在Cache中,Spring大量运用了Cache的手段,在循环依赖问题的解决过程中甚至使用了“三级缓存”。
“三级缓存”主要是指
/** Cache of singleton objects: bean name --> bean instance 已经初始化完成的实例*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
/** Cache of early singleton objects: bean name --> bean instance 只完成构造方法,还没有注入属性的bean*/
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
从字面意思来说:singletonObjects指单例对象的cache,singletonFactories指单例对象工厂的cache,earlySingletonObjects指提前曝光的单例对象的cache
。以上三个cache构成了三级缓存,Spring就用这三级缓存巧妙的解决了循环依赖问题。
Spring首先从singletonObjects(一级缓存)中尝试获取,如果获取不到并且对象在创建中,则尝试从earlySingletonObjects(二级缓存)中获取,如果还是获取不到并且允许从singletonFactories通过getObject获取,即通过singletonFactory#getObject()(三级缓存)获取,
如果三级缓存都获取不到,则创建新的bean
。singletonObjects,singletonFactories,earlySingletonObjects是互斥的,即一个bean只能存在于三者之一。如果bean被放入了earlySingletonObjects中则同时会remove singletonFactories中的bean。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
Spring解决循环依赖的诀窍就在于singletonFactories这个cache,这个cache中存的是类型为ObjectFactory(一个类似于FactoryBean的东西,可以通过getObject获取对象)
此处就是解决循环依赖的关键,这段代码发生在createBeanInstance之后,也就是说单例对象此时已经被创建出来的。这个对象已经被生产出来了,虽然还不完美(还没有进行初始化的第二步和第三步),但是已经能被人认出来了(根据对象引用能定位到堆中的对象),所以Spring此时将这个对象提前曝光。
这样做有什么好处呢?让我们来分析一下“A的某个field或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象”这种循环依赖的情况。A首先完成了初始化的第一步(反射调用构造方法获得对象),并且将自己提前曝光到singletonFactories中,此时进行初始化的第二步,发现自己依赖对象B,此时就尝试去get(B),发现B还没有被create,所以走create流程,B在初始化第一步的时候发现自己依赖了对象A,于是尝试get(A),尝试一级缓存singletonObjects(肯定没有,因为A还没初始化完全),尝试二级缓存earlySingletonObjects(也没有),尝试三级缓存singletonFactories,由于A通过ObjectFactory将自己提前曝光了,所以B能够通过ObjectFactory#getObject拿到A对象,B拿到A对象后顺利完成了初始化阶段1、2、3,完全初始化之后将自己放入到一级缓存singletonObjects中。此时返回A中,A此时能拿到B的对象顺利完成自己的初始化阶段2、3,最终A也完成了初始化,进去了一级缓存singletonObjects中,而且更加幸运的是,由于B拿到了A的对象引用,所以B中的A对象完成了初始化;
而“A的构造方法中依赖了B的实例对象,同时B的构造方法中依赖了A的实例对象”,A、B都在构造函数时需要拿到对方,而构造函数为执行完就无法使bean提前曝光,没放入singletonFacories中。
为什么用到三级缓存
首先,使用两级缓存看起来也是可以解决循环依赖问题的,将只调用了构造方法创建出来的bean放在earlySingletonObjects,将初始化完成的bean放在singletonObjects中。似乎也能解决。
但为什么还需要使用singletonFactories呢?主要原因是便于扩展,在doCreateBean()方法中通过反射(createBeanInstance)创建完bean后,如果允许提前曝光bean则将bean的ObjectFactory放入singletonFactories中。
//截取自AbstractAutowireCapableBeanFactory#doCreateBean()
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
而ObjectFactory的getObject方法主要是通过以下方法实现(getEarlyBeanReference( )):
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;
}
- 其实这个方法里没做什么,将通过反射(createBeanInstance)创建完的bean传入其中,用各种BeanPostProcessor处理bean,如果没有processor则原封不动的返回bean。也就是说使用singletonFactories的好处就是可以调用后置处理器,便于用户处理,AOP的advice也是在这里织入bean。
bean被加入缓存的时间
- bean被加入三级缓存singletonFactories 是在创建bean(createBean方法)过程中,当利用构造器反射创建完成bean后,将bean加入singletonFactories中,然后才执行注入属性的操作;
- 加入二级缓存earlySingletonObjects 是在BeanFactory#getBean()方法第一次尝试从缓存中获取bean时,getSingleton()方法:按顺序从一级、二级、三级缓存中获取,如果从三级缓存中获取到了,则加入二级缓存并返回,如果没有从三级缓存中获取到,则执行createBean创建新对象。
2.3.2 原型模式(Prototye)的循环依赖
在Spring中,@Controller默认都是单例的(singleton)。所谓单例,就是Spring的IOC机制只创建该类的一个实例,每次请求,都会用这同一个实例进行处理,因此若存在全局变量(成员变量),本次请求的值肯定会影响下一次请求时该变量的值。
使用成员变量后,若不想影响下次请求,就需要用到原型模式,即在Controller上加@Scope(“prototype”)
原型模式,指的是每次调用时,会重新创建该类的一个实例,比较类似于我们自己自己new的对象实例。
Spring对原型模式循环依赖的处理策略:
在原型模式下,如果存在A中有B的属性,B中有A的属性,那么当依赖注入的时候,就会产生A还未创建完的时候因为对于B的创建再次返回创建A,造成循环依赖,所以在加载bean时,原型模式需要判断当前bean的所有依赖是否已被创建,如果创建了(即发生循环依赖)会抛出异常。只有在单例情况下才会尝试解决循环依赖。
在spring中解决循环依赖只对单例有效,而对于prototype的bean,spring没有好的解决办法,唯一要做的就是抛出异常
。
在单例模式中Spring通过缓存来解决循环依赖,而在原型模式中,由于每次调用都会创建一个对象,所以对象数量是不可控的,且每一个prototype都需要是全新的,因而无法进行缓存,所以Spring没有处理原型模式下的循环依赖。
仔细思考一下,其实prototype的循环引用其实不一定是有意义的。
singleton中持有prototype,prototype中持有singleton,spring是可以支持的。但是singleton中持有的prototype始终是同一个对象,这样似乎也就失去了prototype的意义。
prototype1中持有prototype2,prototype2中持有prototype1,spring不支持。当prototype1发现自己依赖prototype2,那么去创建prototype2,而prototype2发现自己依赖prototype1,又去创建prototype1,就会无限创建下去。因为每一个prototype都需要是全新的。所以spring不允许prototype的循环依赖。
参考:https://blog.csdn.net/f641385712/article/details/92801300