Merge branch '6.2.x'

This commit is contained in:
Sébastien Deleuze 2025-07-01 11:02:54 +02:00
commit fb214bb74a
2 changed files with 28 additions and 5 deletions

View File

@ -101,7 +101,7 @@ public class SpringFactoriesLoader {
private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class); private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
static final Map<ClassLoader, Map<String, SpringFactoriesLoader>> cache = new ConcurrentReferenceHashMap<>(); static final Map<ClassLoader, Map<String, Factories>> cache = new ConcurrentReferenceHashMap<>();
private final @Nullable ClassLoader classLoader; private final @Nullable ClassLoader classLoader;
@ -319,10 +319,11 @@ public class SpringFactoriesLoader {
Assert.hasText(resourceLocation, "'resourceLocation' must not be empty"); Assert.hasText(resourceLocation, "'resourceLocation' must not be empty");
ClassLoader resourceClassLoader = (classLoader != null ? classLoader : ClassLoader resourceClassLoader = (classLoader != null ? classLoader :
SpringFactoriesLoader.class.getClassLoader()); SpringFactoriesLoader.class.getClassLoader());
Map<String, SpringFactoriesLoader> loaders = cache.computeIfAbsent( Map<String, Factories> factoriesCache = cache.computeIfAbsent(
resourceClassLoader, key -> new ConcurrentReferenceHashMap<>()); resourceClassLoader, key -> new ConcurrentReferenceHashMap<>());
return loaders.computeIfAbsent(resourceLocation, key -> Factories factories = factoriesCache.computeIfAbsent(resourceLocation, key ->
new SpringFactoriesLoader(classLoader, loadFactoriesResource(resourceClassLoader, resourceLocation))); new Factories(loadFactoriesResource(resourceClassLoader, resourceLocation)));
return new SpringFactoriesLoader(classLoader, factories.byType());
} }
protected static Map<String, List<String>> loadFactoriesResource(ClassLoader classLoader, String resourceLocation) { protected static Map<String, List<String>> loadFactoriesResource(ClassLoader classLoader, String resourceLocation) {
@ -654,4 +655,8 @@ public class SpringFactoriesLoader {
} }
} }
private record Factories(Map<String, List<String>> byType) {
}
} }

View File

@ -25,6 +25,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.assertj.core.extractor.Extractors;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
@ -166,9 +167,26 @@ class SpringFactoriesLoaderTests {
void sameCachedResultIsUsedForDefaultClassLoaderAndNullClassLoader() { void sameCachedResultIsUsedForDefaultClassLoaderAndNullClassLoader() {
SpringFactoriesLoader forNull = SpringFactoriesLoader.forDefaultResourceLocation(null); SpringFactoriesLoader forNull = SpringFactoriesLoader.forDefaultResourceLocation(null);
SpringFactoriesLoader forDefault = SpringFactoriesLoader.forDefaultResourceLocation(ClassUtils.getDefaultClassLoader()); SpringFactoriesLoader forDefault = SpringFactoriesLoader.forDefaultResourceLocation(ClassUtils.getDefaultClassLoader());
assertThat(forNull).isSameAs(forDefault); assertThat(forNull).extracting("factories").isSameAs(Extractors.byName("factories").apply(forDefault));
} }
@Test
void staleClassLoaderIsUsedWithCachedResult() {
ClassLoader defaultClassLoader = ClassUtils.getDefaultClassLoader();
ClassLoader cl1 = new ClassLoader() {
};
SpringFactoriesLoader factories1 = SpringFactoriesLoader.forDefaultResourceLocation(defaultClassLoader);
assertThat(factories1).extracting("classLoader").isEqualTo(defaultClassLoader);
ClassLoader previousClassLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(cl1);
SpringFactoriesLoader factories2 = SpringFactoriesLoader.forDefaultResourceLocation(null);
assertThat(factories2).extracting("classLoader").isNull();
}
finally {
Thread.currentThread().setContextClassLoader(previousClassLoader);
}
}
@Nested @Nested
class FailureHandlerTests { class FailureHandlerTests {