Description
Eric Sirianni opened SPR-10936 and commented
In our application, we instantiate multiple Spring ApplicationContext
scoped to a particular tenant, each using the same @Configuration
class. The expectation is that singleton @Beans
produced by the @Configuration
will be scoped to each individual (per-tenant) ApplicationContext
instance. However, we are observing situations where singletons instantiated from the @Configuration
are incorrectly shared across ApplicationContext
instances.
I've narrowed it down to situations where the ApplicationContext
s are instantiated concurrently. This JUnit test exhibits the issue (testSequential passes, testConcurrent fails):
public class ConcurrentConfigurationInitializationTest {
private static AtomicInteger COUNTER = new AtomicInteger(0);
@Configuration
public static class TestConfig {
@Bean
public Integer foo() {
return Integer.valueOf(COUNTER.incrementAndGet());
}
}
@Test
public void testSequential() throws InterruptedException {
test(10, 1);
}
@Test
public void testConcurrent() throws InterruptedException {
test(10, 10);
}
private void test(int numContexts, int numThreads) throws InterruptedException {
final Set<Integer> uniqueBeans = new HashSet<Integer>();
ExecutorService executor = Executors.newFixedThreadPool(numThreads);
for (int i = 0; i < numContexts; i++) {
executor.submit(new Runnable() {
@Override
public void run() {
ApplicationContext context = new AnnotationConfigApplicationContext(TestConfig.class);
Integer bean = (Integer) context.getBean("foo");
uniqueBeans.add(bean);
}
});
}
executor.shutdown();
executor.awaitTermination(60, TimeUnit.SECONDS);
assertThat(uniqueBeans).hasSize(numContexts);
}
}
I would guess that Spring is properly creating a CGLIB-enhanced @Configuration
class per ApplicationContext
and that the issue is that CGLIB itself is not behaving properly in a multithreaded scenario. Perhaps CGLIB callbacks are getting intermingled between proxies. #14439 seems somewhat relevant in this regard.
Affects: 3.2.4
Attachments:
Issue Links:
- Concurrent creation of the same Configuration class in different contexts is not thread-safe [SPR-10307] #14941 Concurrent creation of the same Configuration class in different contexts is not thread-safe ("duplicates")