个人随笔
目录
一个简单的例子来探寻Spring实例化bean执行源码的主脉络(四):解决循环依赖
2021-08-12 22:27:05

前面我们知道了Spring对象的实例化过程,现在我们通过源码看看,其实还是比较简单的,关键点在于提前对象提前暴露出去了。我们来根据源码跟踪下。

一、前提准备

大家可以根据我的前面几篇博文大概弄清楚一下Spring实例化过程

一个简单的例子来探寻Spring实例化bean执行源码的主脉络(一):this()方法
一个简单的例子来探寻Spring实例化bean执行源码的主脉络(二):解析配置类
一个简单的例子来探寻Spring实例化bean执行源码的主脉络(三):扫包和实例化

构造器模式的循环依赖是解决不了的,因为只有bean先执行完构造方法获得对象后,才能够将对象提前暴露出去,所以如果是构造器模式的循环依赖的话,是会直接抛出异常的。

所以这篇文章只会考虑属性注入模式的循环依赖。

二、例子

例子很简单

1、配置类

  1. @Configuration
  2. @ComponentScan(basePackages = "com.suibibk.spring")
  3. public class SpringConfiguration {
  4. //spring容器初始化时,会调用配置类的无参构造函数
  5. public SpringConfiguration(){
  6. System.out.println("容器启动初始化");
  7. }
  8. }

2、启动类

  1. public class App {
  2. public static void main(String[] args) {
  3. ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class);
  4. }
  5. }

3、循环依赖

  1. @Component
  2. public class User {
  3. @Autowired
  4. private User2 user2;
  5. }
  1. @Component
  2. public class User2 {
  3. @Autowired
  4. private User user;
  5. }

三、源码跟踪

1、User类的实例化

根据前几篇博文,我们很容易知道实例化是在

  1. protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
  2. throws BeanCreationException {
  3. ...
  4. // Eagerly cache singletons to be able to resolve circular references
  5. // even when triggered by lifecycle interfaces like BeanFactoryAware.
  6. boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
  7. isSingletonCurrentlyInCreation(beanName));
  8. if (earlySingletonExposure) {
  9. if (logger.isTraceEnabled()) {
  10. logger.trace("Eagerly caching bean '" + beanName +
  11. "' to allow for resolving potential circular references");
  12. }
  13. addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
  14. }
  15. // Initialize the bean instance.
  16. Object exposedObject = bean;
  17. try {
  18. populateBean(beanName, mbd, instanceWrapper);
  19. exposedObject = initializeBean(beanName, exposedObject, mbd);
  20. }
  21. catch (Throwable ex) {
  22. if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
  23. throw (BeanCreationException) ex;
  24. }
  25. else {
  26. throw new BeanCreationException(
  27. mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
  28. }
  29. }
  30. ...
  31. return exposedObject;
  32. }

我把很多无关紧要的代码省略了,这里解决循环依赖的重点是

  1. boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
  2. isSingletonCurrentlyInCreation(beanName));
  3. if (earlySingletonExposure) {
  4. if (logger.isTraceEnabled()) {
  5. logger.trace("Eagerly caching bean '" + beanName +
  6. "' to allow for resolving potential circular references");
  7. }
  8. addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
  9. }
  1. protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
  2. Assert.notNull(singletonFactory, "Singleton factory must not be null");
  3. synchronized (this.singletonObjects) {
  4. if (!this.singletonObjects.containsKey(beanName)) {
  5. this.singletonFactories.put(beanName, singletonFactory);
  6. this.earlySingletonObjects.remove(beanName);
  7. this.registeredSingletons.add(beanName);
  8. }
  9. }
  10. }

这里把bean对象包装成一个 ObjectFactory放到了三级缓存

  1. this.singletonFactories.put(beanName, singletonFactory);

然后在后面这个User对象要注入User2对象,然后User2对象又要注入User对象的时候就可以通过singletonFactories里面获得 ObjectFactory对象调用getEarlyBeanReference(beanName, mbd, bean)返回了。

这里提一下spring的三级缓存是

  1. singletonObjects#一级缓存,就是我们的bean容器
  2. earlySingletonObjects#二级缓存
  3. singletonFactories#三级缓存

放进三级缓存后,User对象继续执行,这里执行到了

  1. populateBean(beanName, mbd, instanceWrapper);

方法,这里就是对这个对象的属性进行注入。我们跟进去

  1. protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
  2. ...
  3. PropertyDescriptor[] filteredPds = null;
  4. if (hasInstAwareBpps) {
  5. if (pvs == null) {
  6. pvs = mbd.getPropertyValues();
  7. }
  8. for (BeanPostProcessor bp : getBeanPostProcessors()) {
  9. if (bp instanceof InstantiationAwareBeanPostProcessor) {
  10. InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
  11. PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
  12. if (pvsToUse == null) {
  13. if (filteredPds == null) {
  14. filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
  15. }
  16. pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
  17. if (pvsToUse == null) {
  18. return;
  19. }
  20. }
  21. pvs = pvsToUse;
  22. }
  23. }
  24. }
  25. ...

这里只看关键的代码,这里会调用这个代码来进行处理,那此时ibp是什么对象呢

  1. PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);

我们还记得在this()方法的时候有初始化几个后置处理器,其中有一个是

  1. org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor

就是用来处理@Autowired注解的,我们跟踪进去

  1. @Override
  2. public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
  3. //获得要注入的元数据,也就是User2
  4. InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
  5. try {
  6. metadata.inject(bean, beanName, pvs);
  7. }
  8. catch (BeanCreationException ex) {
  9. throw ex;
  10. }
  11. catch (Throwable ex) {
  12. throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
  13. }
  14. return pvs;
  15. }

继续

  1. public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
  2. Collection<InjectedElement> checkedElements = this.checkedElements;
  3. Collection<InjectedElement> elementsToIterate =
  4. (checkedElements != null ? checkedElements : this.injectedElements);
  5. if (!elementsToIterate.isEmpty()) {
  6. for (InjectedElement element : elementsToIterate) {
  7. if (logger.isTraceEnabled()) {
  8. logger.trace("Processing injected element of bean '" + beanName + "': " + element);
  9. }
  10. element.inject(target, beanName, pvs);
  11. }
  12. }
  13. }
  1. @Override
  2. protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
  3. Field field = (Field) this.member;
  4. Object value;
  5. if (this.cached) {
  6. value = resolvedCachedArgument(beanName, this.cachedFieldValue);
  7. }
  8. else {
  9. DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
  10. desc.setContainingClass(bean.getClass());
  11. Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
  12. Assert.state(beanFactory != null, "No BeanFactory available");
  13. TypeConverter typeConverter = beanFactory.getTypeConverter();
  14. try {
  15. value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
  16. }
  17. catch (BeansException ex) {
  18. throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
  19. }
  20. synchronized (this) {
  21. if (!this.cached) {
  22. if (value != null || this.required) {
  23. this.cachedFieldValue = desc;
  24. registerDependentBeans(beanName, autowiredBeanNames);
  25. if (autowiredBeanNames.size() == 1) {
  26. String autowiredBeanName = autowiredBeanNames.iterator().next();
  27. if (beanFactory.containsBean(autowiredBeanName) &&
  28. beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
  29. this.cachedFieldValue = new ShortcutDependencyDescriptor(
  30. desc, autowiredBeanName, field.getType());
  31. }
  32. }
  33. }
  34. else {
  35. this.cachedFieldValue = null;
  36. }
  37. this.cached = true;
  38. }
  39. }
  40. }
  41. if (value != null) {
  42. ReflectionUtils.makeAccessible(field);
  43. field.set(bean, value);
  44. }
  45. }
  46. }

我们跟踪这行代码

  1. value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
  1. @Override
  2. @Nullable
  3. public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
  4. @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
  5. descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
  6. if (Optional.class == descriptor.getDependencyType()) {
  7. return createOptionalDependency(descriptor, requestingBeanName);
  8. }
  9. else if (ObjectFactory.class == descriptor.getDependencyType() ||
  10. ObjectProvider.class == descriptor.getDependencyType()) {
  11. return new DependencyObjectProvider(descriptor, requestingBeanName);
  12. }
  13. else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
  14. return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
  15. }
  16. else {
  17. Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
  18. descriptor, requestingBeanName);
  19. if (result == null) {
  20. result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
  21. }
  22. return result;
  23. }
  24. }

再跟踪这行代码

  1. result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
  1. @Nullable
  2. public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
  3. @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
  4. InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
  5. try {
  6. Object shortcut = descriptor.resolveShortcut(this);
  7. if (shortcut != null) {
  8. return shortcut;
  9. }
  10. Class<?> type = descriptor.getDependencyType();
  11. Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
  12. if (value != null) {
  13. if (value instanceof String) {
  14. String strVal = resolveEmbeddedValue((String) value);
  15. BeanDefinition bd = (beanName != null && containsBean(beanName) ?
  16. getMergedBeanDefinition(beanName) : null);
  17. value = evaluateBeanDefinitionString(strVal, bd);
  18. }
  19. TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
  20. try {
  21. return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
  22. }
  23. catch (UnsupportedOperationException ex) {
  24. // A custom TypeConverter which does not support TypeDescriptor resolution...
  25. return (descriptor.getField() != null ?
  26. converter.convertIfNecessary(value, type, descriptor.getField()) :
  27. converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
  28. }
  29. }
  30. Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
  31. if (multipleBeans != null) {
  32. return multipleBeans;
  33. }
  34. Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
  35. if (matchingBeans.isEmpty()) {
  36. if (isRequired(descriptor)) {
  37. raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
  38. }
  39. return null;
  40. }
  41. String autowiredBeanName;
  42. Object instanceCandidate;
  43. if (matchingBeans.size() > 1) {
  44. autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
  45. if (autowiredBeanName == null) {
  46. if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
  47. return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
  48. }
  49. else {
  50. // In case of an optional Collection/Map, silently ignore a non-unique case:
  51. // possibly it was meant to be an empty collection of multiple regular beans
  52. // (before 4.3 in particular when we didn't even look for collection beans).
  53. return null;
  54. }
  55. }
  56. instanceCandidate = matchingBeans.get(autowiredBeanName);
  57. }
  58. else {
  59. // We have exactly one match.
  60. Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
  61. autowiredBeanName = entry.getKey();
  62. instanceCandidate = entry.getValue();
  63. }
  64. if (autowiredBeanNames != null) {
  65. autowiredBeanNames.add(autowiredBeanName);
  66. }
  67. if (instanceCandidate instanceof Class) {
  68. instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
  69. }
  70. Object result = instanceCandidate;
  71. if (result instanceof NullBean) {
  72. if (isRequired(descriptor)) {
  73. raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
  74. }
  75. result = null;
  76. }
  77. if (!ClassUtils.isAssignableValue(type, result)) {
  78. throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
  79. }
  80. return result;
  81. }
  82. finally {
  83. ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
  84. }
  85. }

再跟踪这行代码

  1. if (instanceCandidate instanceof Class) {
  2. instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
  3. }
  1. public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
  2. throws BeansException {
  3. return beanFactory.getBean(beanName);
  4. }

这里就到getBean了,也就开始去获得User2
然后User2也会执行一下上面的流程,最终User2也要注入User,执行到这里的代码,去获取user,此时走进去会到这个逻辑

  1. @SuppressWarnings("unchecked")
  2. protected <T> T doGetBean(
  3. String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
  4. throws BeansException {
  5. String beanName = transformedBeanName(name);
  6. Object bean;
  7. Object sharedInstance = getSingleton(beanName);
  8. ...
  9. }

记住,这里已经是User2去获取User了,所以这里是获取User对象,我们再回忆一下流程
1、先是实例化User对象,发现需要User2属性
2、然后去获取User2对象,发现需要User属性
3、然后去获取User对象

此时代码执行到的是第三步骤,我们在第一步骤的时候已经把User放到了singletonFactories中,我们点进去看

  1. @Nullable
  2. protected Object getSingleton(String beanName, boolean allowEarlyReference) {
  3. Object singletonObject = this.singletonObjects.get(beanName);
  4. if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
  5. synchronized (this.singletonObjects) {
  6. singletonObject = this.earlySingletonObjects.get(beanName);
  7. if (singletonObject == null && allowEarlyReference) {
  8. //这里有
  9. ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
  10. if (singletonFactory != null) {
  11. singletonObject = singletonFactory.getObject();
  12. this.earlySingletonObjects.put(beanName, singletonObject);
  13. this.singletonFactories.remove(beanName);
  14. }
  15. }
  16. }
  17. }
  18. return singletonObject;
  19. }

此时singletonObjects是没有的,但是singletonFactory是有的,毕竟前面放进去了,所以会执行

  1. singletonObject = singletonFactory.getObject();

这个会回调

  1. addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

的getEarlyBeanReference(beanName, mbd, bean)方法,我们点进去

  1. protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
  2. Object exposedObject = bean;
  3. if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
  4. for (BeanPostProcessor bp : getBeanPostProcessors()) {
  5. if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
  6. SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
  7. exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
  8. }
  9. }
  10. }
  11. return exposedObject;
  12. }

这里就返回了我们之前的未完成初始化的User对象,完美解决了循环依赖。

 202

啊!这个可能是世界上最丑的留言输入框功能~


当然,也是最丑的留言列表

有疑问发邮件到 : suibibk@qq.com 侵权立删
Copyright : 个人随笔   备案号 : 粤ICP备18099399号-2