spring源码学习之bean的加载(一)
对XML文件的解析基本上已经大致的走了一遍,虽然没有能吸收多少,但是脑子中总是有些印象的,接下来看下spring中的bean的加载,这个比xml解析复杂的多。
这个加载,在我们使用的时候基本上是:
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("beanFactory.xml"));
MyTestBean bean = (MyTestBean) beanFactory.getBean("myTestBean"); // 这个是bean的加载的使用
一、总体掌握
看看spring中的代码是如何实现的:
这个是在org.springframework.beans.factory.support包下的AbstractBeanFactory类
1 @Override 2 public Object getBean(String name) throws BeansException { 3 return doGetBean(name, null, null, false); 4 } 5 6 /** 7 * Return an instance, which may be shared or independent, of the specified bean. 8 * @param name the name of the bean to retrieve 9 * @param requiredType the required type of the bean to retrieve 10 * @param args arguments to use when creating a bean instance using explicit arguments 11 * (only applied when creating a new instance as opposed to retrieving an existing one) 12 * @param typeCheckOnly whether the instance is obtained for a type check, 13 * not for actual use 14 * @return an instance of the bean 15 * @throws BeansException if the bean could not be created 16 */ 17 @SuppressWarnings("unchecked") 18 protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, 19 @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { 20 21 // 提取对应的beanName 22 final String beanName = transformedBeanName(name); 23 Object bean; 24 25 /** 26 * 检查缓存中或者实例工厂中是否有对应的实例 27 * 为什么会首先使用这段代码呢? 28 * 因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候是为了避免循环依赖 29 *spring创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光 30 * 也就是将ObjectFactory加入缓存中,一旦下个bean创建的时候需要依赖上个bean,则直接使用ObjectFactory 31 */ 32 // Eagerly check singleton cache for manually registered singletons. 33 // 直接尝试从缓存中获取或者singletonFactories中ObjectFactory中获取 34 Object sharedInstance = getSingleton(beanName); 35 if (sharedInstance != null && args == null) { 36 if (logger.isDebugEnabled()) { 37 if (isSingletonCurrentlyInCreation(beanName)) { 38 logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + 39 "' that is not fully initialized yet - a consequence of a circular reference"); 40 } 41 else { 42 logger.debug("Returning cached instance of singleton bean '" + beanName + "'"); 43 } 44 } 45 // 返回对应的实例,有时候存在诸如BeanFactory的情况并不是直接返回实例本身而是返回指定方法返回的实例 46 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); 47 } 48 49 else { 50 // Fail if we're already creating this bean instance: 51 // We're assumably within a circular reference. 52 /** 53 * 只有在单例的情况下才会尝试解决循环依赖,原型模式下, 54 * 如果存在A中有B的属性,B中有A的属性,那么当依赖注入的时候,就会产生 55 * 当A还未创建完的时候,创建B,再次返回创建A,造成循环依赖,下面这种错误,抛出异常 56 */ 57 if (isPrototypeCurrentlyInCreation(beanName)) { 58 throw new BeanCurrentlyInCreationException(beanName); 59 } 60 61 // Check if bean definition exists in this factory. 62 BeanFactory parentBeanFactory = getParentBeanFactory(); 63 // 在parentBeanFactory中检测 64 if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { 65 // Not found -> check parent. 66 String nameToLookup = originalBeanName(name); 67 // 递归到BeanFactory中查找 68 if (parentBeanFactory instanceof AbstractBeanFactory) { 69 return ((AbstractBeanFactory) parentBeanFactory).doGetBean( 70 nameToLookup, requiredType, args, typeCheckOnly); 71 } 72 else if (args != null) { 73 // Delegation to parent with explicit args. 74 return (T) parentBeanFactory.getBean(nameToLookup, args); 75 } 76 else { 77 // No args -> delegate to standard getBean method. 78 return parentBeanFactory.getBean(nameToLookup, requiredType); 79 } 80 } 81 82 // 如果不是仅仅做类型检查则是创建bean,这里需要记录 83 if (!typeCheckOnly) { 84 markBeanAsCreated(beanName); 85 } 86 87 try { 88 // 将存储XML配置文件GenericBeanDefinition转换为RootBeanDefinition 89 // BeanName是子Bean的话同时会合并父类的相关属性 90 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); 91 checkMergedBeanDefinition(mbd, beanName, args); 92 93 // Guarantee initialization of beans that the current bean depends on. 94 String[] dependsOn = mbd.getDependsOn(); 95 // 若存在依赖则需要递归实例化依赖bean 96 if (dependsOn != null) { 97 for (String dep : dependsOn) { 98 if (isDependent(beanName, dep)) { 99 throw new BeanCreationException(mbd.getResourceDescription(), beanName, 100 "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); 101 } 102 // 缓存依赖调用 103 registerDependentBean(dep, beanName); 104 try { 105 getBean(dep); 106 } 107 catch (NoSuchBeanDefinitionException ex) { 108 throw new BeanCreationException(mbd.getResourceDescription(), beanName, 109 "'" + beanName + "' depends on missing bean '" + dep + "'", ex); 110 } 111 } 112 } 113 114 // Create bean instance. 115 // 实例化依赖的bean后便可以实例化mbd本身了 116 // singleton模式的创建 117 if (mbd.isSingleton()) { 118 sharedInstance = getSingleton(beanName, () -> { 119 try { 120 return createBean(beanName, mbd, args); 121 } 122 catch (BeansException ex) { 123 // Explicitly remove instance from singleton cache: It might have been put there 124 // eagerly by the creation process, to allow for circular reference resolution. 125 // Also remove any beans that received a temporary reference to the bean. 126 destroySingleton(beanName); 127 throw ex; 128 } 129 }); 130 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 131 } 132 // Prototype模式创建 133 else if (mbd.isPrototype()) { 134 // It's a prototype -> create a new instance. 135 Object prototypeInstance = null; 136 try { 137 beforePrototypeCreation(beanName); 138 prototypeInstance = createBean(beanName, mbd, args); 139 } 140 finally { 141 afterPrototypeCreation(beanName); 142 } 143 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); 144 } 145 // 指定scope上实例化bean 146 else { 147 String scopeName = mbd.getScope(); 148 final Scope scope = this.scopes.get(scopeName); 149 if (scope == null) { 150 throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); 151 } 152 try { 153 Object scopedInstance = scope.get(beanName, () -> { 154 beforePrototypeCreation(beanName); 155 try { 156 return createBean(beanName, mbd, args); 157 } 158 finally { 159 afterPrototypeCreation(beanName); 160 } 161 }); 162 bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); 163 } 164 catch (IllegalStateException ex) { 165 throw new BeanCreationException(beanName, 166 "Scope '" + scopeName + "' is not active for the current thread; consider " + 167 "defining a scoped proxy for this bean if you intend to refer to it from a singleton", 168 ex); 169 } 170 } 171 } 172 catch (BeansException ex) { 173 cleanupAfterBeanCreationFailure(beanName); 174 throw ex; 175 } 176 } 177 178 // Check if required type matches the type of the actual bean instance. 179 // 检查需要的类型是否符合bean的实例类型 180 if (requiredType != null && !requiredType.isInstance(bean)) { 181 try { 182 T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType); 183 if (convertedBean == null) { 184 throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); 185 } 186 return convertedBean; 187 } 188 catch (TypeMismatchException ex) { 189 if (logger.isDebugEnabled()) { 190 logger.debug("Failed to convert bean '" + name + "' to required type '" + 191 ClassUtils.getQualifiedName(requiredType) + "'", ex); 192 } 193 throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); 194 } 195 } 196 return (T) bean; 197 }
(1)转换对应的beanName
这里传入的参数name并不一定是beanName,可能是别名,也可能是FactoryBean,所以进行一系类的解析,这些解析内容如下
1)去除FactoryBean的修饰符,也就是name="&aa",那么首先会去除&,而使name=aa
2)取指定别名所表示的最终的beanName
(2)尝试从缓存中加载单例
单例在spring的同一个容器内只会被创建一次,后续在获取bean,就直接从单例缓存中获取了,当然,这里也只是尝试加载,
首先尝试从缓存中加载,如果加载不成功则再次尝试从singletonFactories中加载。因为在创建单例bean的时候会存在依赖注入的情况
而在创建依赖的时候为了避免循环依赖,在spring中创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光加入
到缓存中,一旦下一个bean创建的时候需要依赖上一个bean则直接使用ObjectFactory
(3)bean的实例化
如果缓存中得到了bean的原始状态,则需要对bean进行实例化,缓存中的记录只是最原始的bean状态,并不一定是我们最终想要的bean,
举个例子,假如我们想对工厂bean进行处理,那么这里得到的是工厂bean的初始状态,但是我们真正想要的是工厂bean定义的factory-method
方法中返回的bean,而getObjectForBeanInstance就是完成这个工作的
(4)原型模式的依赖检查
只有在单例情况下才会尝试解决循环依赖,如果存在A中有B的属性,B中有A的属性,那么当依赖注入的时候,就会产生当A还没创建完成的时候,因为
对B的创建再次返回创建A,造成循环依赖,也就是(isPrototypeCurrentlyInCreation(beanName))为true的情况
(5)检测parentBeanFactory
从代码上看,如果缓存没有数据的话,直接转到父类工厂上去加载了,这是为什么?可能我们忽略了
parentBeanFactory != null && !containsBeanDefinition(beanName)这里面判断条件,parentBeanFactory != null,parentBeanFactory如果为空,
其他一切都是浮云,但是还有一个条件,!containsBeanDefinition(beanName),它是在检测如果当前加载的XML配置文件中,不包含beanName多对应的
配置,只能去parentBeanFactory中尝试,然后再去递归的调用递归方法
(6)将存储XML配置文件GenericBeanDefinition转换为RootBeanDefinition
因为从XML配置文件中读取到的bean信息存储在GenericBeanDefinition中,但是所有的bean的后续处理都是针对于RootBeanDefinition,
所以这里需要进行一个转换,转换的同时,如果父类bean不为空的话,则会一并合并父类属性
(7)寻找依赖
因为bean的初始化过程很肯能用到某些属性,而某些属性可能是动态配置的,并且配置成依赖其他的bean,那么这个时候必须先加载依赖的bean,
spring的加载顺序中,在初始化一个bean的时候,首先会初始化这个bean所对应的依赖
(8)针对不同的scope进行bean的创建
spring根据不同的配置进行不同的初始化策略,默认的是singleton
(9)类型转换
程序到这里已经基本结束了,通常对该方法的调用参数requireType是为空的,但是可能会存在这样的情况,返回的bean其实是个String,但是
requireType却传入的是Integer类型,那么这时候本步骤就起作用了,他的功能是将返回的bean转换为requireType所指定的类型。
二、剥离,逐一分析
1、FactoryBean的使用
一般情况下,spring通过反射机制,利用bean的class属性指定实现类来实例化bean。在某些情况下,实例化bean的过程比较复杂,按照传统的方式,
则需要在bean的配置中提供大量的配置信息,配置方式的灵活性是受限的,spring为此提供了一个org.springframework.beans.factory.FactoryBean
工厂类接口,用户可以实现该接口定制实例化bean的逻辑
FactoryBean接口对于spring来说,占有重要地位,spring自身就提供了70多个FactoryBean的实现,从spring 3.0开始,FactoryBean开始支持泛型
接口声明为:
1 public interface FactoryBean<T> { 2 T getObject() throws Exception; 3 Class<?> getObjectType(); 4 default boolean isSingleton() { 5 return true; 6 } 7 }
接口中定义的三个方法:
1)T getObject():返回由FactoryBean创建的bean实例,如果isSignleton()返回的是true,则该实例会方放到spring容器中单实例缓存池中
2)default boolean isSingleton():判断创建bean的scope
3)Class<?> getObjectType():返回创建bean的类型
2、缓存中获取单例bean
单例在spring的同一容器中只会被创建一次,然后再获取bean直接从单例缓存中获取,当然,这里也只是尝试加载,首先尝试从缓存中加载,
然后再次尝试从singletonFactories中加载,因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,
spring创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光加入到缓存中,一旦下一个bean创建的时候依赖上个bean
则直接使用ObjectFactory
下面的额源码是在org.springframework.beans.factory.support包下DefaultSingletonBeanRegistry中
1 @Override 2 @Nullable 3 public Object getSingleton(String beanName) { 4 return getSingleton(beanName, true); 5 } 6 7 /** 8 * Return the (raw) singleton object registered under the given name. 9 * <p>Checks already instantiated singletons and also allows for an early 10 * reference to a currently created singleton (resolving a circular reference). 11 * @param beanName the name of the bean to look for 12 * @param allowEarlyReference whether early references should be created or not 13 * @return the registered singleton object, or {@code null} if none found 14 */ 15 @Nullable 16 protected Object getSingleton(String beanName, boolean allowEarlyReference) { 17 // 检查缓存中是否存在实例 18 Object singletonObject = this.singletonObjects.get(beanName); 19 if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { 20 // 如果为空,则锁定全局变量并进行处理 21 synchronized (this.singletonObjects) { 22 // 如果此bean正在加载则不处理 23 singletonObject = this.earlySingletonObjects.get(beanName); 24 if (singletonObject == null && allowEarlyReference) { 25 // ObjectFactory初始化策略存储在singletonFactories 26 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); 27 if (singletonFactory != null) { 28 // 调用预先设定好的getObject()方法 29 singletonObject = singletonFactory.getObject(); 30 // 记录在缓存中earlySingletonObjects和singletonFactories互斥 31 this.earlySingletonObjects.put(beanName, singletonObject); 32 this.singletonFactories.remove(beanName); 33 } 34 } 35 } 36 } 37 return singletonObject; 38 }
这个方法首先尝试从singletonObjects里面获取实例,如果获取不到,再从earlySingletonObjects中获取,如果还获取不到,尝试从
singletonFactories中获取beanName对应的ObjectFactory,然后调用这个ObjectFactory的getObject()来创建bean,并放到earlySingletonObjects中去,
并且从singletonFactories中remove掉ObjectFactory,而对于后续的所有内存操作都只为了循环依赖检测时候使用,这里有几个不同的map:
singletonObjects:用于保存BeanName和创建bean实例之间的关系,bean name -> bean instance
singletonFactories:用于保存BeanName和创建bean工厂之间的关系,bean name -> ObjectFactory
earlySingletonObjects:用于保存BeanName和创建bean实例之间的关系,与ingletonObjects不同的是,当一个单例bean被放到这里面后,那么当bean
还在创建过程中,就可以通过getBean方法获取到了,其目的是用来检测循环引用
registeredSingletons:用来保存所有当前已存在的bean
3、从bean的实例中获取对象
在getBean()方法中,getObjectForBeanInstance是个高频使用的方法,无论是从缓存中获取bean还是根据不同的scope策略加载bean,总之,得到bean
的实例后,我们第一步要做的就是调用这个方法来检测一下正确性,其实就是用于检测当前bean是否是FactoryBean类型的bean,如果是,那么需要调用该
bean对应的FactoryBean实例中的getObject()作为返回值
无论是从缓存中获取到bean还是从不同的scope策略中加载的bean都是最原始的bean状态,并不一定是我们最终想要的bean,而getObjectForBeanInstance
方法就是完成这个工作的
该方法是在org.springframework.beans.factory.support包下的AbstractBeanFactory类:
1 protected Object getObjectForBeanInstance( 2 Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { 3 4 // Don't let calling code try to dereference the factory if the bean isn't a factory. 5 // 如果指定的name是工厂相关(以&为前缀)且beanInstance又不是FactoryBean类型则验证不通过 6 if (BeanFactoryUtils.isFactoryDereference(name)) { 7 if (beanInstance instanceof NullBean) { 8 return beanInstance; 9 } 10 if (!(beanInstance instanceof FactoryBean)) { 11 throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass()); 12 } 13 } 14 15 // Now we have the bean instance, which may be a normal bean or a FactoryBean. 16 // If it's a FactoryBean, we use it to create a bean instance, unless the 17 // caller actually wants a reference to the factory. 18 // 现在我们有了一个bean的实例,这个实例可能是正常的bean或者是FactoryBean类型的 19 // 如果是FactoryBean我们使用它创建实例 20 // 但是如果用户想要直接获取工厂实例而不是工厂的getObject()方法对应的实例,那么传入的name应该加入前缀& 21 if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) { 22 return beanInstance; 23 } 24 25 Object object = null; 26 if (mbd == null) { 27 // 尝试从缓存中加载bean 28 object = getCachedObjectForFactoryBean(beanName); 29 } 30 if (object == null) { 31 // Return bean instance from factory. 32 // 到这里已经明确知道beanInstance一定是FactoryBean 33 FactoryBean<?> factory = (FactoryBean<?>) beanInstance; 34 // Caches object obtained from FactoryBean if it is a singleton. 35 // containsBeanDefinition检测beanDefinitionMap中也就是所有已经记载的类中检测是否定义beanName 36 if (mbd == null && containsBeanDefinition(beanName)) { 37 // 将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition 38 // 如果指定BeanName 是子bean的话同时合并父类的相关属性 39 mbd = getMergedLocalBeanDefinition(beanName); 40 } 41 // 是否是用户定义的,而不是应用程序本身定义的 42 boolean synthetic = (mbd != null && mbd.isSynthetic()); 43 object = getObjectFromFactoryBean(factory, beanName, !synthetic); 44 } 45 return object; 46 }
这个方法其实大部分代码是在做一些功能性判断,真正的核心的代码交给了getObjectFromFactoryBean()方法来处理
此方法是在org.springframework.beans.factory.support包下的FactoryBeanRegistrySupport类
这个和作者在书中的源码有些不同的地方,应该是做了一些优化,注意一下这个地方,有些源码还是不懂为啥那么做
1 /** 2 * Obtain an object to expose from the given FactoryBean. 3 * @param factory the FactoryBean instance 4 * @param beanName the name of the bean 5 * @param shouldPostProcess whether the bean is subject to post-processing 6 * @return the object obtained from the FactoryBean 7 * @throws BeanCreationException if FactoryBean object creation failed 8 * @see org.springframework.beans.factory.FactoryBean#getObject() 9 */ 10 protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) { 11 // 如果是单例模式 12 if (factory.isSingleton() && containsSingleton(beanName)) { 13 synchronized (getSingletonMutex()) { 14 // 从缓存中获取bean实例 15 Object object = this.factoryBeanObjectCache.get(beanName); 16 if (object == null) { 17 // 从工厂bean中获取bean实例 18 object = doGetObjectFromFactoryBean(factory, beanName); 19 // Only post-process and store if not put there already during getObject() call above 20 // (e.g. because of circular reference processing triggered by custom getBean calls) 21 Object alreadyThere = this.factoryBeanObjectCache.get(beanName); 22 if (alreadyThere != null) { 23 object = alreadyThere; 24 } 25 else { 26 if (shouldPostProcess) { 27 if (isSingletonCurrentlyInCreation(beanName)) { 28 // Temporarily return non-post-processed object, not storing it yet.. 29 return object; 30 } 31 beforeSingletonCreation(beanName); 32 try { 33 object = postProcessObjectFromFactoryBean(object, beanName); 34 } 35 catch (Throwable ex) { 36 throw new BeanCreationException(beanName, 37 "Post-processing of FactoryBean's singleton object failed", ex); 38 } 39 finally { 40 afterSingletonCreation(beanName); 41 } 42 } 43 if (containsSingleton(beanName)) { 44 this.factoryBeanObjectCache.put(beanName, object); 45 } 46 } 47 } 48 return object; 49 } 50 } 51 else { 52 Object object = doGetObjectFromFactoryBean(factory, beanName); 53 if (shouldPostProcess) { 54 // bean需要做后续处理 55 try { 56 object = postProcessObjectFromFactoryBean(object, beanName); 57 } 58 catch (Throwable ex) { 59 throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex); 60 } 61 } 62 return object; 63 } 64 }
从工厂中获取bean实例的代码在doGetObjectFromFactoryBean()方法中,来看看
此方法是在org.springframework.beans.factory.support包下的FactoryBeanRegistrySupport类
1 /** 2 * Obtain an object to expose from the given FactoryBean. --> 获得一个bean实例从所给的工厂bean中 3 * @param factory the FactoryBean instance 4 * @param beanName the name of the bean 5 * @return the object obtained from the FactoryBean 6 * @throws BeanCreationException if FactoryBean object creation failed 7 * @see org.springframework.beans.factory.FactoryBean#getObject() 8 */ 9 private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName) 10 throws BeanCreationException { 11 12 Object object; 13 try { 14 // 需要权限验证 access是权限的意思 15 if (System.getSecurityManager() != null) { 16 AccessControlContext acc = getAccessControlContext(); 17 try { 18 object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc); 19 } 20 catch (PrivilegedActionException pae) { 21 throw pae.getException(); 22 } 23 } 24 else { 25 // 在工厂中创建bean实例 26 object = factory.getObject(); 27 } 28 } 29 catch (FactoryBeanNotInitializedException ex) { 30 throw new BeanCurrentlyInCreationException(beanName, ex.toString()); 31 } 32 catch (Throwable ex) { 33 throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex); 34 } 35 36 // Do not accept a null value for a FactoryBean that's not fully 37 // initialized yet: Many FactoryBeans just return null then. 38 if (object == null) { 39 if (isSingletonCurrentlyInCreation(beanName)) { 40 throw new BeanCurrentlyInCreationException( 41 beanName, "FactoryBean which is currently in creation returned null from getObject"); 42 } 43 object = new NullBean(); 44 } 45 return object; 46 }
这个能得到实例化的bean了,但是根据shouldPostProcess来进行后续的bean处理,走的是postProcessObjectFromFactoryBean()方法
org.springframework.beans.factory.support包下的FactoryBeanRegistrySupport类,这个是抽象类,找到实现该方法的类,那就是
org.springframework.beans.factory.support包下的AbstractAutowireCapableBeanFactory类,看一下这个类中源码实现:
1 /** 2 * Applies the {@code postProcessAfterInitialization} callback of all 3 * registered BeanPostProcessors, giving them a chance to post-process the 4 * object obtained from FactoryBeans (for example, to auto-proxy them). 5 * @see #applyBeanPostProcessorsAfterInitialization 6 */ 7 @Override 8 protected Object postProcessObjectFromFactoryBean(Object object, String beanName) { 9 return applyBeanPostProcessorsAfterInitialization(object, beanName); 10 } 11 12 @Override 13 public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) 14 throws BeansException { 15 16 Object result = existingBean; 17 for (BeanPostProcessor processor : getBeanPostProcessors()) { 18 Object current = processor.postProcessAfterInitialization(result, beanName); 19 if (current == null) { 20 return result; 21 } 22 result = current; 23 } 24 return result; 25 }
对于后续处理操作,作者在这里没有详细介绍,后续会有详细介绍,这里就不详细讲解了,我也没法记下来,只能跟着作者的思路来进行探索了,
这里作者提出了一条总结:spring获取bean的规则只有一条:尽可能保证所有bean初始化后都会调用注册的BeanPostProcessor的postProcessAfterInitialization
方法进行处理,也就是上面方法中的Object current = processor.postProcessAfterInitialization(result, beanName);这一行代码,可以针对此特性设计自己的
设计逻辑
4、获取单例
之前我们讲解了从缓存中获取单例的过程,那么,如果缓存中不存在已经加载的单例bean,就需要从头开始bean的加载过程了,而spring中使用了
getSingleton()的重载方法实现bean的加载过程
1 /** 2 * Return the (raw) singleton object registered under the given name, 3 * creating and registering a new one if none registered yet. 4 * @param beanName the name of the bean 5 * @param singletonFactory the ObjectFactory to lazily create the singleton 6 * with, if necessary 7 * @return the registered singleton object 8 */ 9 public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { 10 Assert.notNull(beanName, "Bean name must not be null"); 11 // 全局变量需要同步 12 synchronized (this.singletonObjects) { 13 // 首先检查对应的bean是否已经加载过,因为singleton模式其实就是复用以创建的bean,所以这一步是必须的 14 Object singletonObject = this.singletonObjects.get(beanName); 15 // 如果为空才可以进行singleton的bean的初始化 16 if (singletonObject == null) { 17 if (this.singletonsCurrentlyInDestruction) { 18 throw new BeanCreationNotAllowedException(beanName, 19 "Singleton bean creation not allowed while singletons of this factory are in destruction " + 20 "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); 21 } 22 if (logger.isDebugEnabled()) { 23 logger.debug("Creating shared instance of singleton bean '" + beanName + "'"); 24 } 25 beforeSingletonCreation(beanName); 26 boolean newSingleton = false; 27 boolean recordSuppressedExceptions = (this.suppressedExceptions == null); 28 if (recordSuppressedExceptions) { 29 this.suppressedExceptions = new LinkedHashSet<>(); 30 } 31 try { 32 // 初始化bean 33 singletonObject = singletonFactory.getObject(); 34 newSingleton = true; 35 } 36 catch (IllegalStateException ex) { 37 // Has the singleton object implicitly appeared in the meantime -> 38 // if yes, proceed with it since the exception indicates that state. 39 singletonObject = this.singletonObjects.get(beanName); 40 if (singletonObject == null) { 41 throw ex; 42 } 43 } 44 catch (BeanCreationException ex) { 45 if (recordSuppressedExceptions) { 46 for (Exception suppressedException : this.suppressedExceptions) { 47 ex.addRelatedCause(suppressedException); 48 } 49 } 50 throw ex; 51 } 52 finally { 53 if (recordSuppressedExceptions) { 54 this.suppressedExceptions = null; 55 } 56 afterSingletonCreation(beanName); 57 } 58 if (newSingleton) { 59 // 加入缓存中 60 addSingleton(beanName, singletonObject); 61 } 62 } 63 return singletonObject; 64 } 65 }
上述代码中其实使用了回调方法,使得程序可以在单例创建的前后做一些准备及处理操作,而真正的获取单例bean的方法其实并不是在此方法中实现,
其逻辑是在ObjectFactory类型的实例singletonFactory中实现的,而这些准备和处理操作包括如下:
(1)检查缓存中是否已经加载过
(2)若没有加载,则记录beanName的正在加载状态
(3)加载单例前记录加载状态
可能你会觉得beforeSingletonCreation方法是个空实现,里面没有任何逻辑,但其实不是,这个函数中做了一个很重要的操作:记录加载状态,也就是
通过this.singletonsCurrentlyInCreation.add(beanName)将当前正要创建的bean记录在缓存中,这样就可以对循环依赖进行检测 同一个类中
1 protected void beforeSingletonCreation(String beanName) { 2 if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { 3 throw new BeanCurrentlyInCreationException(beanName); 4 } 5 }
(4)通过调用参数传入的ObjectFactory的个体Object方法实例化bean
(5)加载单例后的处理方法调用
同步骤3的记录加载状态相似,当bean加载结束后需要移除缓存中对该bean的正在加载状态的记录,同一个类中
1 protected void afterSingletonCreation(String beanName) { 2 if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) { 3 throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation"); 4 } 5 }
(6)将结果记录至缓存并删除加载bean过程中所记录的各种辅助状态 同一个类中
1 protected void addSingleton(String beanName, Object singletonObject) { 2 synchronized (this.singletonObjects) { 3 this.singletonObjects.put(beanName, singletonObject); 4 this.singletonFactories.remove(beanName); 5 this.earlySingletonObjects.remove(beanName); 6 this.registeredSingletons.add(beanName); 7 } 8 }
(7)返回处理结果
虽然我们了解了加载bean的逻辑架构,但是现在我们并没有开始对bean加载功能进行探索,之前提到过,bean的加载逻辑实在传入的ObjectFactory类型的参数
singletonFactory中定义的,我们反推参数的获取,得到以下代码:这我就不会往回反推参数,全局搜索的。。。
这段代码是在org.springframework.beans.factory.support包下AbstractBeanFactory类中,doGetBean()方法
1 sharedInstance = getSingleton(beanName, () -> { 2 try { 3 return createBean(beanName, mbd, args); 4 } 5 catch (BeansException ex) { 6 // Explicitly remove instance from singleton cache: It might have been put there 7 // eagerly by the creation process, to allow for circular reference resolution. 8 // Also remove any beans that received a temporary reference to the bean. 9 destroySingleton(beanName); 10 throw ex; 11 } 12 });
ObjectFactory的核心部分只调用了createBean()方法,继续探索createBean()
5、准备创建bean
这里作者提出了一点在探索spring源码的过程中的一点规律:一个真正干活的函数其实是以do开头的,比如doGetObjectFromFactoryBean,而给我们错觉的函数
getObjectFromFactoryBean,其实只是从全局角度去做一些统筹工作,这个规则对createBean也不例外,看createBean如何统筹工作:
1 /** 2 * Central method of this class: creates a bean instance, 3 * populates the bean instance, applies post-processors, etc. 4 * @see #doCreateBean 5 */ 6 @Override 7 protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) 8 throws BeanCreationException { 9 10 if (logger.isDebugEnabled()) { 11 logger.debug("Creating instance of bean '" + beanName + "'"); 12 } 13 RootBeanDefinition mbdToUse = mbd; 14 15 // Make sure bean class is actually resolved at this point, and 16 // clone the bean definition in case of a dynamically resolved Class 17 // which cannot be stored in the shared merged bean definition. 18 // 锁定class,根据设置的class属性或者根据beanName来解析Class,具体在实现逻辑在resolveBeanClass()方法中 19 Class<?> resolvedClass = resolveBeanClass(mbd, beanName); 20 if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { 21 mbdToUse = new RootBeanDefinition(mbd); 22 mbdToUse.setBeanClass(resolvedClass); 23 } 24 25 // Prepare method overrides. 26 // 验证及准备覆盖方法 27 try { 28 // 29 mbdToUse.prepareMethodOverrides(); 30 } 31 catch (BeanDefinitionValidationException ex) { 32 throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), 33 beanName, "Validation of method overrides failed", ex); 34 } 35 36 try { 37 // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. 38 // 给BeanPostProcessors一个机会来返回代理来替代真正的实例 39 Object bean = resolveBeforeInstantiation(beanName, mbdToUse); 40 if (bean != null) { 41 return bean; 42 } 43 } 44 catch (Throwable ex) { 45 throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, 46 "BeanPostProcessor before instantiation of bean failed", ex); 47 } 48 49 try { 50 // 真正的创建bean的代码在这个方法中 51 Object beanInstance = doCreateBean(beanName, mbdToUse, args); 52 if (logger.isDebugEnabled()) { 53 logger.debug("Finished creating instance of bean '" + beanName + "'"); 54 } 55 return beanInstance; 56 } 57 catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) { 58 // A previously detected exception with proper bean creation context already, 59 // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry. 60 throw ex; 61 } 62 catch (Throwable ex) { 63 throw new BeanCreationException( 64 mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex); 65 } 66 }
来看下具体步骤和功能
(1)根据设置的class属性或者是beanName来解析Class
(2)对override属性进行标记和验证
这个其实spring中没有override-method这样的配置,但是spring是存在lookup-method和replace-method的,而这两个配置的加载其实
就是将配置统一存放到BeanDefinition中的methodOverride属性里,这个函数的操作其实就是针对这两个属性
(3)应用初始化前的后处理器,解析指定bean是否存在初始化前的短路操作
(4)创建bean
5.1 处理override属性
prepareMethodOverrides()方法在org.springframework.beans.factory.support包下的AbstractBeanDefinition类中
1 public void prepareMethodOverrides() throws BeanDefinitionValidationException { 2 // Check that lookup methods exists. 3 if (hasMethodOverrides()) { 4 Set<MethodOverride> overrides = getMethodOverrides().getOverrides(); 5 synchronized (overrides) { 6 for (MethodOverride mo : overrides) { 7 prepareMethodOverride(mo); 8 } 9 } 10 } 11 } 12 13 //继续看prepareMethodOverride(mo)方法的源码,在同一个类中: 14 /** 15 * Validate and prepare the given method override. 16 * Checks for existence of a method with the specified name, 17 * marking it as not overloaded if none found. 18 * @param mo the MethodOverride object to validate 19 * @throws BeanDefinitionValidationException in case of validation failure 20 */ 21 protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException { 22 // 获取对应类中对应方法名的个数 23 int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName()); 24 if (count == 0) { 25 throw new BeanDefinitionValidationException( 26 "Invalid method override: no method with name '" + mo.getMethodName() + 27 "' on class [" + getBeanClassName() + "]"); 28 } 29 else if (count == 1) { 30 // Mark override as not overloaded, to avoid the overhead of arg type checking. 31 // 标记MethodOverride暂未被覆盖,避免参数类型的检查的开销 32 mo.setOverloaded(false); 33 } 34 }
spring是存在lookup-method和replace-method的,而这两个配置的加载其实就是将配置统一存放到BeanDefinition中的methodOverride属性里,
这两个方法的实现原理是在bean实例化的时候检测到存在MethodOverride,会动态的为当前bean生成动态代理并使用对应的拦截器为bean做增强处理,
相关逻辑实现在bean的实例化部分详细及讲解
但是,对于方法的匹配来讲,如果一个类中存在若干个重载方法,那么,在函数调用及增强的时候,还需要根据参数类型进行匹配,来最终确认当前调用的是
哪个函数。但是,spring将一部分匹配工作在这里完成了,如果当前类中的方法只有一个,那么就设置重载方法没有重载,这样在后续调用的时候便可以直接
使用找到的方法,而不需要进行方法的参数匹配验证了,而且还可以提前对方法存在性进行验证。
5.2 实例化的前置处理
在真正调用doCreat方法创建bean之前调用了一个代理的方法,resolveBeforeInstantiation(beanName, mbdToUse),对BeanDefinition中属性做了前置处理,
当然,无论其中是否有逻辑实现,我们都可以理解,因为真正的逻辑实现前后留有处理函数,也是可扩展的一种体现,但是,这并不是最重要的,在函数中
还提供了一个短路判断,这才是最关键的部分(TODO:这里不是很懂,为什么这个短路操作最关键!!!)
if (bean != null) {
return bean;
}
当前置处理返回的结果如果不为空,那么直接略过后续的bean的创建而直接返回结果,这一特性虽然很容易被忽略,但是起着至关重要的作用,我们熟悉的AOP功能
就是在这里判断的
org.springframework.beans.factory.support包下AbstractAutowireCapableBeanFactory类中resolveBeforeInstantiation方法
1 /** 2 * Apply before-instantiation post-processors, resolving whether there is a 3 * before-instantiation shortcut for the specified bean. 4 * @param beanName the name of the bean 5 * @param mbd the bean definition for the bean 6 * @return the shortcut-determined bean instance, or {@code null} if none 7 */ 8 @Nullable 9 protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) { 10 Object bean = null; 11 // 如果尚未被解析 12 if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) { 13 // Make sure bean class is actually resolved at this point. 14 if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { 15 Class<?> targetType = determineTargetType(beanName, mbd); 16 if (targetType != null) { 17 bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName); 18 if (bean != null) { 19 bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); 20 } 21 } 22 } 23 mbd.beforeInstantiationResolved = (bean != null); 24 } 25 return bean; 26 }
此方法中最吸引人的方法是applyBeanPostProcessorsBeforeInstantiation以及applyBeanPostProcessorsAfterInitialization方法,两个方法的实现非常简单,
无非是对后处理器中的所有InstantiationAwareBeanPostProcessor类型的后处理器进行postProcessBeforeInstantiation方法和BeanPostProcessor类型的
postProcessAfterInitialization方法的调用
(1)实例化前的后处理应用
bean的实例化前调用,也就是将AbstractBeanDefinition转换为BeanWrapper前处理,给子类一个修改BeanDefinition的机会,也就是说,bean通过这个方法处理之后
可能不是我们之前的bean了
1 @Nullable 2 protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) { 3 for (BeanPostProcessor bp : getBeanPostProcessors()) { 4 if (bp instanceof InstantiationAwareBeanPostProcessor) { 5 InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; 6 Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName); 7 if (result != null) { 8 return result; 9 } 10 } 11 } 12 return null; 13 }
(2)实例化后的后处理应用
在讲解从缓存中获取单例bean的时候提过,spring中的规则是在bean的初始化后尽可能保证将注册的后处理器postProcessAfterInitialization方法应用到bean中,
因为如果返回的bean不为空,那么便不会再次经历普通bean的创建过程,所以只能在这里应用后处理器的postProcessAfterInitialization方法
1 在讲解从缓存中获取单例bean的时候提过,spring中的规则是在bean的初始化后尽可能保证将注册的后处理器postProcessAfterInitialization方法应用到bean中, 2 因为如果返回的bean不为空,那么便不会再次经历普通bean的创建过程,所以只能在这里应用后处理器的postProcessAfterInitialization方法 3 @Override 4 public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) 5 throws BeansException { 6 7 Object result = existingBean; 8 for (BeanPostProcessor processor : getBeanPostProcessors()) { 9 Object current = processor.postProcessAfterInitialization(result, beanName); 10 if (current == null) { 11 return result; 12 } 13 result = current; 14 } 15 return result; 16 }
6、循环依赖
6.1什么是循环依赖
循环依赖就是循环引用,就是两个或者多个bean 相互之间的持有对方,比如:CircleA调用了CircleB,CircleB引用了CircleC,CircleC引用了CircleA,则
他们最终反应成一个环,此处不是循环调用,循环调用是方法之前的调用
6.2spring如何解决循环依赖
spring容器循环依赖包括构造器循环依赖和setter循环依赖,首先来定义一下循环引用类:
1 public class TestA{ 2 3 private TestB testB; 4 5 public void a(){ 6 testB.b(); 7 } 8 9 public void setTestB(TestB testB){ 10 this.testB = testB; 11 } 12 13 public TestB getTestB(){ 14 return testB; 15 } 16 } 17 18 public class TestB{ 19 20 private TestC testC; 21 22 public void b(){ 23 testC.c(); 24 } 25 26 public void setTestC(TestC testC){ 27 this.testC = testC; 28 } 29 30 public TestC getTestC(){ 31 return testC; 32 } 33 } 34 35 public class TestC{ 36 37 private TestA testA; 38 39 public void c(){ 40 testA.a(); 41 } 42 43 public void setTestA(TestA testA){ 44 this.testA = testA; 45 } 46 47 public TestA getTestA(){ 48 return testA; 49 } 50 }
spring 中将循环依赖的处理分成了三种情况:
(1)构造器循环依赖
表示通过构造器注入构成的循环依赖,次依赖是无法解决的,只能抛出异常BeanCurrentlyInCreationException异常表示循环依赖
如在创建TestA类时,构造器需要TestB,在创建TestB 时又发现需要TestC,则又去创建TestC,最终在创建TestC时发现又需要TestA,从而形成一个环,没法创建
spring容器将每一个正在创建的bean标识符放在一个“当前创建bean池”,bean标识符在创建过程中将一直保持在这个池中,因此如果在创建过程中发现自己已经在
“当前创建bean池”中,将抛出BeanCurrentlyInCreationException异常表示循环依赖;而对于创建完毕的bean将从“当前创建bean池”中清除掉
看一段配置文件,来分析一下其中的,在spring中的创建过程 这其实就是上面代码在xml中的翻译
<bean id="testA" class="com.bean.TestA">
<constructor-arg index="0" ref="testB" />
</bean>
<bean id="testB" class="com.bean.TestB">
<constructor-arg index="0" ref="testC" />
</bean>
<bean id="testC" class="com.bean.testC">
<constructor-arg index="0" ref="testA" />
</bean>
解析:
spring容器创建“testA”bean,首先去“当前创建bean池”查找是否当前bean正在创建,如果没发现,则继续准备其需要的构造器参数”testB“,并将”testA“
标识符当到“当前创建bean池”
spring容器创建“testB”bean,首先去“当前创建bean池”查找是否当前bean正在创建,如果没发现,则继续准备其需要的构造器参数”testC“,并将”testB“
标识符当到“当前创建bean池”
spring容器创建“testC”bean,首先去“当前创建bean池”查找是否当前bean正在创建,如果没发现,则继续准备其需要的构造器参数”testA“,并将”testC“
标识符当到“当前创建bean池”,但是当去创建testA时,发现该bean标识符在“当前创建bean池”中,因为表示循环依赖,抛出BeanCurrentlyInCreationException
(2)setter循环依赖
表示通过setter注入的方式形成的循环依赖,对于setter注入造成的依赖是通过spring容器提前暴露刚完成的构造器注入但未完成其他步骤(setter注入)的
bean来完成的,而且只能解决单例作用域的bean循环依赖。通过提前暴露一个单例工厂方法,从而使得其他bean能引用到该bean,如下代码:
1 addSingletonFactory(beanName, new ObjectFactory(){ 2 public Object getObject(){ 3 return getEarlyBeanRefrence(beanName,mbd,bean); 4 } 5 });
具体步骤分析:
spring容器创建“testA”bean,首先根据无参构造器创建bean,并暴露一个“ObjectFactory”,用于返回一个提前暴露一个创建中的bean,并将“testA”标识符
当到“当前创建bean池”,然后进行setter注入“testB”
spring容器创建“testB”bean,首先根据无参构造器创建bean,并暴露一个“ObjectFactory”,用于返回一个提前暴露一个创建中的bean,并将“testB”标识符
当到“当前创建bean池”,然后进行setter注入“circle”
spring容器创建“testC”bean,首先根据无参构造器创建bean,并暴露一个“ObjectFactory”,用于返回一个提前暴露一个创建中的bean,并将“testC”标识符
当到“当前创建bean池”,然后进行setter注入“testA”,进行注入“testA”时由于提前暴露了“ObjectFactory”工厂,从而使它返回提前暴露一个创建中的bean
最后在依赖注入“testA”和“testB”,完成依赖注入
(3)protoType范围的依赖处理
对于“protoType”作用域bean,spring容器无法完成依赖注入,因为spring容器不进行缓存“protoType”作用域的bean,因此无法暴露一个创建中的bean
对于“singleston”作用域的bean,可以通过“setAllowCircularReferences(false)”来禁用循环引用
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,携手博客园推出1Panel与Halo联合会员
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· MySQL下200GB大表备份,利用传输表空间解决停服发版表备份问题
· 记一次 .NET某固高运动卡测试 卡慢分析
· 微服务架构学习与思考:微服务拆分的原则
· 记一次 .NET某云HIS系统 CPU爆高分析
· 如果单表数据量大,只能考虑分库分表吗?
· 7 个最近很火的开源项目「GitHub 热点速览」
· DeepSeekV3:写代码很强了
· 记一次 .NET某固高运动卡测试 卡慢分析
· Visual Studio 2022 v17.13新版发布:强化稳定性和安全,助力 .NET 开发提
· MySQL下200GB大表备份,利用传输表空间解决停服发版表备份问题