Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
spring-issuemaster opened this issue Apr 19, 2015 · 3 comments

Comments

Projects
None yet
2 participants
@spring-issuemaster
Copy link
Collaborator

commented Apr 19, 2015

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:

  • INT-3543 Fix tests do not close ApplicationContext between test methods
  • #17517 ApplicationContext fails to load in TestNG test if previous test is annotated with @DirtiesContext
  • #17012 DefaultListableBeanFactory should allow efficient access to current bean names

Referenced from: commits 706d3ad, 93f403c

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Apr 19, 2015

Sam Brannen commented

This issue is related to INT-3543 and #17012.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Apr 19, 2015

Sam Brannen commented

This issue is potentially related to #17517.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Apr 24, 2015

Juergen Hoeller commented

ApplicationContext.getAutowireCapableBeanFactory() always declared that it may throw IllegalStateException before initialization and after closing. I added a forward-looking notice back in 4.1.2, preparing for consistent throwing from a GenericApplicationContext in 4.2. For some reason I never got around to creating an issue for it, so here we go with this one now :-)

For anyone depending on the previous behavior, i.e. doing getAutowireCapableBeanFactory() calls after closing, such code would have been GenericApplicationContext dependent anyway. Switching such code to ConfigurableApplicationContext.getBeanFactory() should do the job, still returning the underlying BeanFactory without any lifecycle checks.

Juergen

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.