Skip to content

Commit 81be4c2

Browse files
committed
Re-resolve cached arguments in case of NoSuchBeanDefinitionException
Closes spring-projectsgh-26517 (cherry picked from commit 99a1388)
1 parent a17c2cc commit 81be4c2

File tree

2 files changed

+298
-82
lines changed

2 files changed

+298
-82
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java

Lines changed: 105 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -628,45 +628,58 @@ protected void inject(Object bean, @Nullable String beanName, @Nullable Property
628628
Field field = (Field) this.member;
629629
Object value;
630630
if (this.cached) {
631-
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
632-
}
633-
else {
634-
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
635-
desc.setContainingClass(bean.getClass());
636-
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
637-
Assert.state(beanFactory != null, "No BeanFactory available");
638-
TypeConverter typeConverter = beanFactory.getTypeConverter();
639631
try {
640-
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
641-
}
642-
catch (BeansException ex) {
643-
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
632+
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
644633
}
645-
synchronized (this) {
646-
if (!this.cached) {
647-
Object cachedFieldValue = null;
648-
if (value != null || this.required) {
649-
cachedFieldValue = desc;
650-
registerDependentBeans(beanName, autowiredBeanNames);
651-
if (autowiredBeanNames.size() == 1) {
652-
String autowiredBeanName = autowiredBeanNames.iterator().next();
653-
if (beanFactory.containsBean(autowiredBeanName) &&
654-
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
655-
cachedFieldValue = new ShortcutDependencyDescriptor(
656-
desc, autowiredBeanName, field.getType());
657-
}
658-
}
659-
}
660-
this.cachedFieldValue = cachedFieldValue;
661-
this.cached = true;
662-
}
634+
catch (NoSuchBeanDefinitionException ex) {
635+
// Unexpected removal of target bean for cached argument -> re-resolve
636+
value = resolveFieldValue(field, bean, beanName);
663637
}
664638
}
639+
else {
640+
value = resolveFieldValue(field, bean, beanName);
641+
}
665642
if (value != null) {
666643
ReflectionUtils.makeAccessible(field);
667644
field.set(bean, value);
668645
}
669646
}
647+
648+
@Nullable
649+
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
650+
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
651+
desc.setContainingClass(bean.getClass());
652+
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
653+
Assert.state(beanFactory != null, "No BeanFactory available");
654+
TypeConverter typeConverter = beanFactory.getTypeConverter();
655+
Object value;
656+
try {
657+
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
658+
}
659+
catch (BeansException ex) {
660+
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
661+
}
662+
synchronized (this) {
663+
if (!this.cached) {
664+
Object cachedFieldValue = null;
665+
if (value != null || this.required) {
666+
cachedFieldValue = desc;
667+
registerDependentBeans(beanName, autowiredBeanNames);
668+
if (autowiredBeanNames.size() == 1) {
669+
String autowiredBeanName = autowiredBeanNames.iterator().next();
670+
if (beanFactory.containsBean(autowiredBeanName) &&
671+
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
672+
cachedFieldValue = new ShortcutDependencyDescriptor(
673+
desc, autowiredBeanName, field.getType());
674+
}
675+
}
676+
}
677+
this.cachedFieldValue = cachedFieldValue;
678+
this.cached = true;
679+
}
680+
}
681+
return value;
682+
}
670683
}
671684

672685

@@ -695,59 +708,17 @@ protected void inject(Object bean, @Nullable String beanName, @Nullable Property
695708
Method method = (Method) this.member;
696709
Object[] arguments;
697710
if (this.cached) {
698-
// Shortcut for avoiding synchronization...
699-
arguments = resolveCachedArguments(beanName);
700-
}
701-
else {
702-
int argumentCount = method.getParameterCount();
703-
arguments = new Object[argumentCount];
704-
DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
705-
Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
706-
Assert.state(beanFactory != null, "No BeanFactory available");
707-
TypeConverter typeConverter = beanFactory.getTypeConverter();
708-
for (int i = 0; i < arguments.length; i++) {
709-
MethodParameter methodParam = new MethodParameter(method, i);
710-
DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
711-
currDesc.setContainingClass(bean.getClass());
712-
descriptors[i] = currDesc;
713-
try {
714-
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
715-
if (arg == null && !this.required) {
716-
arguments = null;
717-
break;
718-
}
719-
arguments[i] = arg;
720-
}
721-
catch (BeansException ex) {
722-
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
723-
}
711+
try {
712+
arguments = resolveCachedArguments(beanName);
724713
}
725-
synchronized (this) {
726-
if (!this.cached) {
727-
if (arguments != null) {
728-
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
729-
registerDependentBeans(beanName, autowiredBeans);
730-
if (autowiredBeans.size() == argumentCount) {
731-
Iterator<String> it = autowiredBeans.iterator();
732-
Class<?>[] paramTypes = method.getParameterTypes();
733-
for (int i = 0; i < paramTypes.length; i++) {
734-
String autowiredBeanName = it.next();
735-
if (beanFactory.containsBean(autowiredBeanName) &&
736-
beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
737-
cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
738-
descriptors[i], autowiredBeanName, paramTypes[i]);
739-
}
740-
}
741-
}
742-
this.cachedMethodArguments = cachedMethodArguments;
743-
}
744-
else {
745-
this.cachedMethodArguments = null;
746-
}
747-
this.cached = true;
748-
}
714+
catch (NoSuchBeanDefinitionException ex) {
715+
// Unexpected removal of target bean for cached argument -> re-resolve
716+
arguments = resolveMethodArguments(method, bean, beanName);
749717
}
750718
}
719+
else {
720+
arguments = resolveMethodArguments(method, bean, beanName);
721+
}
751722
if (arguments != null) {
752723
try {
753724
ReflectionUtils.makeAccessible(method);
@@ -771,6 +742,59 @@ private Object[] resolveCachedArguments(@Nullable String beanName) {
771742
}
772743
return arguments;
773744
}
745+
746+
@Nullable
747+
private Object[] resolveMethodArguments(Method method, Object bean, @Nullable String beanName) {
748+
int argumentCount = method.getParameterCount();
749+
Object[] arguments = new Object[argumentCount];
750+
DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
751+
Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
752+
Assert.state(beanFactory != null, "No BeanFactory available");
753+
TypeConverter typeConverter = beanFactory.getTypeConverter();
754+
for (int i = 0; i < arguments.length; i++) {
755+
MethodParameter methodParam = new MethodParameter(method, i);
756+
DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
757+
currDesc.setContainingClass(bean.getClass());
758+
descriptors[i] = currDesc;
759+
try {
760+
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
761+
if (arg == null && !this.required) {
762+
arguments = null;
763+
break;
764+
}
765+
arguments[i] = arg;
766+
}
767+
catch (BeansException ex) {
768+
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
769+
}
770+
}
771+
synchronized (this) {
772+
if (!this.cached) {
773+
if (arguments != null) {
774+
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
775+
registerDependentBeans(beanName, autowiredBeans);
776+
if (autowiredBeans.size() == argumentCount) {
777+
Iterator<String> it = autowiredBeans.iterator();
778+
Class<?>[] paramTypes = method.getParameterTypes();
779+
for (int i = 0; i < paramTypes.length; i++) {
780+
String autowiredBeanName = it.next();
781+
if (beanFactory.containsBean(autowiredBeanName) &&
782+
beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
783+
cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
784+
descriptors[i], autowiredBeanName, paramTypes[i]);
785+
}
786+
}
787+
}
788+
this.cachedMethodArguments = cachedMethodArguments;
789+
}
790+
else {
791+
this.cachedMethodArguments = null;
792+
}
793+
this.cached = true;
794+
}
795+
}
796+
return arguments;
797+
}
774798
}
775799

776800

0 commit comments

Comments
 (0)