Skip to content

Autowiring against a closed ApplicationContext should consistently fail [SPR-12932] #17525

Closed
@spring-projects-issues

Description

@spring-projects-issues

Sam Brannen opened SPR-12932 and commented

Status Quo

It is currently possible to autowire against an ApplicationContext that has been closed. However, attempting to do so should result in some sort of exception being thrown. See the example failing tests below.

This issue was brought to our attention when integration tests in the Spring Integration test suite started failing. See INT-3543 for details.


Analysis by Jürgen Höller

AbstractApplicationContext already invokes assertBeanFactoryActive() before it delegates to the internal DefaultListableBeanFactory but of course only for methods on the ApplicationContext itself.

The underlying BeanFactory doesn't have the notion of a 'closed' state -- it may just have had its singletons destroyed but could, from its perspective, recreate them at any point.

The semantically cleaner solution is to perform the assertion in the application context's getAutowireCapableBeanFactory() implementation: AbstractRefreshableApplicationContext subclasses do throw an IllegalStateException there after closing, but GenericApplicationContext subclasses don't. The latter needs to be fixed, and the getAutowireCapableBeanFactory() Javadoc in the ApplicationContext interface needs to explicitly state that an IllegalStateException will be thrown after context closing.


Example Failing Tests

Example1Test does not fail until the second line of the test2() method, thus demonstrating that the test instance was autowired from a closed ApplicationContext.

Example2Test contains a copy of the actual code from DependencyInjectionTestExecutionListener.injectDependencies(), demonstrating that autowiring against a closed ApplicationContext in fact does not throw any kind of exception.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class Example1Test {

    @Configuration static class Config {
        @Bean String foo() { return "foo"; }
    }

    @Autowired ConfigurableApplicationContext context;
    @Autowired String foo;

    @Test
    public void test1() {
        assertEquals("foo", foo);
        assertTrue(context.isActive());
    }

    @After
    public void close() {
        context.close();
    }

    @Test
    public void test2() {
        assertEquals("foo", foo);
        assertTrue(context.isActive());
    }
}
public class Example2Test {

    @Test(expected = Exception.class)
    public void autowiringAgainstClosedContextShouldThrowAnException() {
        ConfigurableApplicationContext context = new GenericApplicationContext();
        context.refresh();
        context.close();

        // Simulate DependencyInjectionTestExecutionListener
        AutowireCapableBeanFactory beanFactory = context.getAutowireCapableBeanFactory();
        beanFactory.autowireBeanProperties(this, AutowireCapableBeanFactory.AUTOWIRE_NO, false);
    }
}

Affects: 4.1.2, 4.1.6

Issue Links:

Referenced from: commits 706d3ad, 93f403c

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: enhancementA general enhancement

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions