随着我们代码中更多服务的出现与依赖关系的耦合,bean与bean之间的交互往往会涉及很多对其他类的依赖。我们通常用简单的Autowired、提供对应依赖对象的setter方法以及构造器中传入需要引用的其他对象,spring就可以完美的做好依赖关系自动装配。那么本节就来分析下spring中是如何完成bean之间这些依赖的自动查找与注入
关于这个话题,最重要的是spring中用到的三级缓存。但spring中的循环依赖情况分很多种,本文会进行不同场景的依次分析。
一级缓存:singletonObjects (存放的是已经完成整个生命周期初始化的对象,是正常getBean方式拿出来的源头)
/** Cache of singleton objects: bean name to bean instance. */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
二级缓存:earlySingletonObjects (暂时放的是通过各种方式实例化出来的对象,属性及初始化方法及后置处理等过程还未进行)
/** Cache of early singleton objects: bean name to bean instance. */ private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
三级缓存:singletonFactories (允许提前暴露引用下用于创建bean的工厂,在代码体现上是一个lamda方法:()->createBean(beanName, mbd, args))
/** Cache of singleton factories: bean name to ObjectFactory. */ private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
单例与单例setter依赖
在spring中,创建的bean如果不指定scope一般默认为单例的。注解依赖方式包括字段级别注解及方法级别注解两种情况,常见A,B依赖代码如下
Bean1:
@Component
public class BeanSetter1 {
@Autowired
private BeanSetter2 beanSetter2;
public void print(){
System.out.println("autowired beanSetter2:"+beanSetter2);
}
Bean2:
@Component
public class BeanSetter2 {
@Autowired
private BeanSetter1 beanSetter1;
public void print(){
System.out.println("autowired beanSetter1:"+beanSetter1);
}
}
启动容器,通过context拿到对应的bean以及其中注入的依赖。其中BeanSetter1与BeanSetter2中的属性都与容器中各自对应的beanSetter是同一个单例对象 对于singleton类型的bean,spring在创建context时会完成对该bean的实例化、初始化、后置处理等一系列过程。在refresh中的finishBeanFactoryInitialization中就是负责对所有满足条件的bean 进行预先创建及缓存过程。 判断条件如下: 非抽象、单例、非懒加载。对FactoryBean还需要满足允许提早初始化 在上面流程中,当beanName为beanSetter1时,getBean() 开始进行BeanSetter1的创建及初始化
缓存获取
第一次从singletonObjects缓存中拿,同时允许查找提前引用缓存allowEarlyReference->singletonFactories DefaultSingletonBeanRegistry
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
可惜现在bean才开始创建并不在缓存中也还未设置开始创建等状态,所以拿出来为空直接返回。接着为创建该bean做一些bd的清除及状态设定 markBeanAsCreated
clearMergedBeanDefinition(beanName)
this.alreadyCreated.add(beanName);
按照bean的scope类型进行不同方式的创建
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
...
return createBean(beanName, mbd, args);
...
);
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
创建bean的开始
在getSingleton中,第二次尝试从singletonObjects中拿依然为空,此时经过bean创建前期的一系列检验及状态的标记后调用ObjectFactory进行bean的真正创建即createBean(beanName, mbd, args)
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException...
}
beforeSingletonCreation(beanName);
boolean newSingleton = false;
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
...
}
catch (BeanCreationException ex) {
...
}
finally {
...
afterSingletonCreation(beanName);
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
对于objectFactory创建bean的过程进行分析, AbstractAutowireCapableBeanFactory
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
mbdToUse.prepareMethodOverrides();
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
return beanInstance
接下来分析doCreateBean的实现过程 AbstractAutowireCapableBeanFactory
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
BeanWrapper instanceWrapper = this.factoryBeanInstanceCache.remove(beanName)
or
createBeanInstance(beanName, mbd, args)
}
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
...
属性的填充与注入
接上面populateBean的内容,针对测试代码这里是由AutowiredAnnotationPostProcessor起作用完成对BeanSetter1中属性对象beanSetter2的查找 InjectionMetadata: 由于我们在属性上设置的Autowired注解,由AutowiredFieldElement负责处理(若在方法上对应AutowiredMethodElement,最后通过方法反射注入值)
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}else{
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
if (!this.cached) {
if (value != null || this.required) {
this.cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
...
{
this.cachedFieldValue = new ShortcutDependencyDescriptor( desc, autowiredBeanName, field.getType());
}
}
}
else {
this.cachedFieldValue = null;
}
this.cached = true;
}
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
属性对象的推断
从beanFactory中查找合适的bean完成属性对象的创建或查找 DefaultListableBeanFactory
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
...
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
非懒加载继续解析查找
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
...
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
...
}
if (matchingBeans.size() > 1) {
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
}else{
}
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
...
return result;
}
findAutowireCandidates中,从容器中查找出所有合适类型的beanName,根据具体类型进行筛选决定
protected Map<String, Object> findAutowireCandidates(
@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
result.put(key,value)
}
...
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
return result;
}
resolvableDependencies列举情况
属性类型的bean创建
在DependencyDescriptor中开始依赖对象的bean查找或创建过程。 此时beanSetter1还处于populateBean阶段,两者在各级缓存中的存在情况如下
| singletonObjects | earlySingletonObjects | singletonFactories |
---|
beanSetter1 | N | N | Y | beanSetter2 | N | N | N |
在前面doResolveDependency中,拿出的instanceCandidate 如果为class类型的对象(还未在缓存中的情况),则需要从beanFactory中拿或者创建依赖的bean实例
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
throws BeansException {
return beanFactory.getBean(beanName);
}
同BeanSetter1的创建过程一样,BeanSetter2的过程中也允许提早暴露自己的对象工厂,会在singletonFactories中加入自己的创建对象方法,此时singletonFactories 存在了两个对象的工厂创建方法。 之后在populateBean时会对依赖属性beanSetter1进行属性的注入查找, 通过beanFactory查找beanSetter1时,会尝试从各级缓存中拿,最终会通过beanSetter1对应的对象工厂创建,得到实例对象后从工厂缓存singletonFactories移除并把实例加到二级缓存earlySingletonObjects
| singletonObjects | earlySingletonObjects | singletonFactories |
---|
beanSetter1 | N | Y | N | beanSetter2 | N | N | Y |
在getEarlyBeanReference中,这里传入的bean就是还处在populateBean阶段的BeanSetter1对象的引用,通过各个SmartInstantiationAwareBeanPostProcessor后置处理器的调用拿到最终的bean(没有改变,依然是传入的原始对象)
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;
}
至此,beanSetter2对象的依赖属性beanSetter1已经得到值(只是这个值是实例化出来的简单对象 ,但指向同一个beanSetter1引用)并返回,继续进行beanSetter2在populateBean阶段的postProcessProperties位置,开始执行后续初始化方法直到整个bean创建完成加入到一级缓存singletonObjects中并返回,标志该bean在spring中创建的完成,可从容器中取出正常使用。
| singletonObjects | earlySingletonObjects | singletonFactories |
---|
beanSetter1 | N | Y | N | beanSetter2 | Y | N | N |
属性填充后续初始化
回到beanSetter1对象的创建,在完成对依赖beanSetter2对象的查找中促使了在容器中的完整创建,现在beanSetter1已经完成了properties的处理填充过程,对应的字段也被spring接入了在容器中合适的对象类型的bean。从populateBean开始继续完成接下来的初始化及后置初始化处理等过程,经过最后一次可能进行代理的后置过程后,beanSetter1进行提早引用的检查是否当前对象被代理更改过
AbstractAutowireCapableBeanFactory doCreateBean
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
...
Object exposedObject = bean;
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
...
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException...
}
}
}
}
...
}
等校验通过后,完成接下来的创建并加入到singletonObjects中,循环依赖结束。
单例与单例构造依赖
在很多场景我们需要直接通过构造方式直接传入强依赖的对象,比如下面构造互相引用代码
非懒加载
BeanCtr1
@Component
public class BeanCtr1 {
private BeanCtr2 beanCtr2;
public BeanCtr1(BeanCtr2 beanCtr2){
this.beanCtr2 = beanCtr2;
}
public void print(){
System.out.println("BeanCtr1 print beanCtr2:"+beanCtr2);
}
}
BeanCtr2
@Component
public class BeanCtr2 {
private BeanCtr1 beanCtr1;
public BeanCtr2(BeanCtr1 beanCtr1) {
this.beanCtr1 = beanCtr1;
}
public void print(){
System.out.println("BeanCtr2 print beanCtr1:"+beanCtr1);
}
}
这样的循环引用可以吗?不行,因为beanCtr1在通过构造方式获得beanInstance查找构造器参数的过程与前面类似(没有懒加载的情况会一直继续直到找出实例为止),最终从当前beanDefinitionMap中找到一个合适类型对应的bean信息即beanCtr2,通过beanFactory的getBean去查找或创建。这就 就要求beanCtr2至少需要在二级缓存中能够暂时被引用。而之前分析过,只有在bean实例化出来后有了BeanWrapper,后续在允许提前引用时才有机会被放到三级缓存singletonFactories中,之后被依赖对象查找时再提升到二级缓存。而被依赖的beanCtr2的创建过程也需要非懒加载的beanCtr1的实例,此时创建beanSetter1因为它已经在创建过程中了,再次标记创建中将会抛出exception
详细过程如下图整理所示
因此如果要用构造器互相依赖成功,需要将构造方法标志为Lazy加载。
懒加载
只需要在先初始化的BeanCtr1构造方法上用Lazy注解 ,在创建BeanCtr1的构造参数依赖时,会将依赖BeanCtr2作为proxy而不再从beanFactory中查找或创建对应BeanCtr2的实例,继续完成之后的初始化等直到加入一级缓存中结束。对BeanCtr2的构造参数非懒加载BeanCtr1,进行正常beanFactory.getBean就已经能找到之前已初始化完在singletonObjetcs中的BeanCtr1。
从上图懒加载过程图中,先构造懒加载proxy buildLazyResolutionProxy时设置具体获取target的逻辑TargetSource到ProxyFactory中,内容为从beanFactory根据依赖描述符解析获取bean。
protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) {
...
final DefaultListableBeanFactory dlbf = (DefaultListableBeanFactory) beanFactory;
TargetSource ts = new TargetSource() {
@Override
public Class<?> getTargetClass() {
return descriptor.getDependencyType();
}
@Override
public boolean isStatic() {
return false;
}
@Override
public Object getTarget() {
Set<String> autowiredBeanNames = (beanName != null ? new LinkedHashSet<>(1) : null);
Object target = dlbf.doResolveDependency(descriptor, beanName, autowiredBeanNames, null);
if (target == null) {
Class<?> type = getTargetClass();
...
if (autowiredBeanNames != null) {
for (String autowiredBeanName : autowiredBeanNames) {
if (dlbf.containsBean(autowiredBeanName)) {
dlbf.registerDependentBean(autowiredBeanName, beanName);
}
}
}
return target;
}
@Override
public void releaseTarget(Object target) {
}
};
ProxyFactory pf = new ProxyFactory();
pf.setTargetSource(ts);
...
return pf.getProxy(dlbf.getBeanClassLoader());
}
在创建proxy中根据config创建合适代理对象
此时config的信息满足hasNoUserSuppliedProxyInterfaces,再根据接口或proxy类型判断用JDK还是cglib代理 optimize:false proxyTargetClass:false interfaces:empty 这里情况将会调用ObjenesisCglibAopProxy进行代理,CglibAopProxy 获得proxy时根据exposeProxy及静态方法类型与否创建如下表的拦截执行方式,去执行真正targetSource中getTarget方法获取对象。 如果代理方法为static,实际上在此时已经直接获取targetSource中的调用结果及真正的目标对象。
| static | non static |
---|
exposeProxy | StaticUnadvisedExposedInterceptor | DynamicUnadvisedExposedInterceptor | not exposeProxy | StaticUnadvisedInterceptor | DynamicUnadvisedInterceptor |
拿到懒加载的代理对象后,当我们需要访问其中的依赖对象时会触发当时的targetSource中的getTarget方法,去从bean中查找对应的依赖bean 当调用beanCtr1的print方法时,
BeanCtr1 beanCtr1 = context.getBean(BeanCtr1.class);
System.out.println(beanCtr1);
beanCtr1.print();
BeanCtr2 beanCtr2 = context.getBean(BeanCtr2.class);
System.out.println(beanCtr2);
beanCtr2.print();
com.example.spring5.BeanCtr1@740fb309
BeanCtr1 print beanCtr2:com.example.spring5.BeanCtr2@5f8e8a9d
com.example.spring5.BeanCtr2@5f8e8a9d
BeanCtr2 print beanCtr1:com.example.spring5.BeanCtr1@740fb3
触发了beanCtr2的toString方法,懒加载的逻辑此时会最终调用从beanFactory中获取beanCtr2单例对象
单例与原型setter依赖
单例与原型的循环依赖可以成功,但根据原型的定义beanSingleton中的引用对象每次拿出来的都不会是同一个原型对象实例。原型对象的实例只会在调用或访问的时候才会创建,不可能出现在三级缓存中任何一个地方。
如下代码 BeanPrototype :
@Component
@Scope("prototype")
public class BeanPrototype {
@Autowired
private BeanSingleton beanSingleton;
public void print(){
System.out.println("BeanPrototype print beanSingleton:"+beanSingleton);
}
}
BeanSingleton:
@Component
public class BeanSingleton {
@Autowired
private BeanPrototype beanPrototype;
public void print(){
System.out.println("BeanSingleton print beanPrototype:"+beanPrototype);
}
}
在初始化BeanPrototype时,由于是原型不属于之前提到的提早初始化条件,不会进行创建因此在容器缓存中没有相关的信息。
!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()
在初始化BeanSingleton时,与之前单例bean过程一样,会将对应创建方法存在三级缓存singletonFactories中,之后在属性设值阶段populateBean会触发对依赖对象BeanPrototype实例的创建,根据容器中beanDefinition的信息进行bean的创建 BeanPrototype被动创建时,不满足earlySingletonExposure情况因此不会加入singletonFactories缓存中自己的工厂方法,执行到对beanSingleton属性的解析时,通过beanFactory.getBean(beanName),按顺序从缓存中拿到之前的创建对象工厂方法获得实例并赋值给属性字段。原型对象的创建接下来正常执行完成,但不会加入到singletonObjects一级缓存中。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
BeanSingleton依赖的对象beanPrototype解析成功后,继续完成单例的剩余初始化过程,直到加入singletonObjects结束。
原型与原型setter依赖
不可以依赖成功,因为原型会因为解决属性依赖时被检测为并发标记创建中,抛出Exception。 测试代码 BeanPrototype1
@Component
@Scope("prototype")
public class BeanPrototype1 {
@Autowired
private BeanPrototype2 beanPrototype2;
public void print(){
System.out.println("BeanPrototype1 print beanPrototype2:"+beanPrototype2);
}
}
BeanPrototype2
@Component
@Scope("prototype")
public class BeanPrototype2 {
@Autowired
private BeanPrototype1 beanPrototype1;
public void print(){
System.out.println("BeanPrototype2 print beanPrototype1:"+beanPrototype1);
}
}
在容器初始化后getq其中一个bean时就会提示你循环依赖错误问题。 主要报错来自如下过程 AbstractBeanFactory
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
Object sharedInstance = getSingleton(beanName);
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
if(singleton){
sharedInstance = getSingleton(beanName, () -> {
return createBean(beanName, mbd, args);});
...
}else if(prototype){
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
afterPrototypeCreation(beanName);
...
}
}
在spring中循环依赖的常见情况已经有了明确的认识后,在之后的使用中就可以正确设置好一些依赖关系避免程序的意外错误。
|