felixoldenburg
10/2/2017 - 7:51 AM

StalledApplicationContext.java

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;

/**
 * A custom {@link AnnotationConfigApplicationContext} which doesn't publish the application startup event per default,
 * so we can simulate a context which hasn't yet started completely.
 *
 * Useful for testing large applications with dozens of components which have to be loaded at startup time.
 * If individual beans are loaded first and pick up their work before the rest of the beans are ready,<p>
 * this could lead do undesired behaviour
 */
public static class StalledApplicationContext extends AnnotationConfigApplicationContext
{
    final AnnotatedBeanDefinitionReader reader;

    final ClassPathBeanDefinitionScanner scanner;

    /** Synchronization monitor for the "refresh" and "destroy" */
    private final Object startupShutdownMonitor = new Object();

    public StalledApplicationContext()
    {
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
        initApplicationEventMulticaster();
    }


    public StalledApplicationContext(Class<?>... annotatedClasses)
    {
        this();
        register(annotatedClasses);
        refresh();
    }


    /**
     * Copied from {@link org.springframework.context.support.AbstractApplicationContext},
     * but skips the finishRefresh() call which triggers the start up event we don't want
     * @throws BeansException
     * @throws IllegalStateException
     */
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                // Don't trigger the ContextRefresh event!
                // finishRefresh();
            }

            catch (BeansException ex) {
                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }
        }
    }
}