Skip to content

Use of same @Configuration class across multiple ApplicationContexts is not threadsafe [SPR-10936] #15564

Closed
@spring-projects-issues

Description

@spring-projects-issues

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 ApplicationContexts 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:

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: bugA general bug

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions