Skip to content

Exception during context refresh swallowed by subsequent LifecycleProcessor exception handling [SPR-10000] #14634

Closed
@spring-projects-issues

Description

@spring-projects-issues

Archie Cobbs opened SPR-10000 and commented

My application had a bug causing an exception to be thrown during construction of a bean.

This caused the application context refresh operation to be aborted. However, in the process of aborting the refresh, an additional exception was thrown by AbstractApplicationContext.getLifecycleProcessor().

This second exception got logged to the error log, but the first exception never did.

As a result, it was very difficult to debug what the actual problem was.

The error logs, including the second exception that did get logged, are here (edited for brevity):

2012-11-15 17:27:29,067 [localhost-startStop-1] INFO : Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@7dbafc22: defining beans [...]; parent: org.springframework.beans.factory.support.DefaultListableBeanFactory@5697c78b
2012-11-15 17:27:29,551 [localhost-startStop-1] INFO : Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@7dbafc22: defining beans [...]; parent: org.springframework.beans.factory.support.DefaultListableBeanFactory@5697c78b
2012-11-15 17:27:29,595 [localhost-startStop-1] INFO : Closing Root WebApplicationContext: startup date [Thu Nov 15 17:27:08 CST 2012]; root of context hierarchy
2012-11-15 17:27:29,607 [localhost-startStop-1] WARN : Exception thrown from LifecycleProcessor on context close
java.lang.IllegalStateException: LifecycleProcessor not initialized - call 'refresh' before invoking lifecycle methods via the context: Root WebApplicationContext: startup date [Thu Nov 15 17:27:08 CST 2012]; root of context hierarchy
        at org.springframework.context.support.AbstractApplicationContext.getLifecycleProcessor(AbstractApplicationContext.java:350)
        at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1038)
        at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:993)
        at org.springframework.context.support.AbstractApplicationContext.destroy(AbstractApplicationContext.java:981)
        at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:211)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:498)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:474)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:509)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:474)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:300)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:609)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:469)
        at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:383)
        at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:283)
        at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:111)
        at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4791)
        at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5285)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
        at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
        at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
        at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:618)
        at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1100)
        at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:1618)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
        at java.util.concurrent.FutureTask.run(FutureTask.java:166)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
        at java.lang.Thread.run(Thread.java:722)

It appears that the following snippet of code in AbstractBeanFactory (visible in the above stack trace) may be contributing to the problem (but I haven't verified that for sure). Note how the second exception occurs during the call to destroySingleton().


            // Create bean instance.
            if (mbd.isSingleton()) {
                sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                    public Object getObject() throws BeansException {
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            // Explicitly remove instance from singleton cache: It might have been put there
                            // eagerly by the creation process, to allow for circular reference resolution.
                            // Also remove any beans that received a temporary reference to the bean.
                            destroySingleton(beanName);
                            throw ex;
                        }
                    }
                });
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }

Possibly relevant: I have a slightly unusual setup where an outer application context contains a bean which is itself an inner application context:

<bean id="updatesContext" class="org.springframework.context.support.ClassPathXmlApplicationContext">
    <constructor-arg>
        <util:list>
            <value>classpath:updates.xml</value>
        </util:list>
    </constructor-arg>
    <constructor-arg>
        <value>false</value>
    </constructor-arg>
    <constructor-arg>
        <bean factory-bean="applicationContextBean" factory-method="getApplicationContext"/>
    </constructor-arg>
</bean>

The applicationContextBean is a bean that exposes the containing application context. It is set as the parent of the nested context. Note the refresh constructor parameter is false, so the inner application context is not refreshed until afterPropertiesSet().

Bottom line: ideally, secondary exceptions should never occur; but if they do, they should never prevent a primary exception from being logged.


Affects: 3.1.2

Attachments:

Issue Links:

Backported to: 3.2.11

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)status: backportedAn issue that has been backported to maintenance branchestype: bugA general bug

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions