NOTE

1. Create the Spring Container

1. Code to analyze 2. Create ApplicationContext and trace the refresh process

JavaCreated Updated 1 min readhistorical

This is a historical learning note and may contain outdated or incomplete understanding.

1. Code to Analyze

public static void main(String[] args)
{
    // Create ApplicationContext.
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AopConfig.class);
    // Obtain the Calc Bean from ApplicationContext.
    Calc calc = applicationContext.getBean(Calc.class);
    // Call div.
    System.out.println(calc.div(10,10));

}

This can be divided into two processes: creating ApplicationContext, and obtaining the Calc Bean from `ApplicationContext). We trace them step by step.

2. Create ApplicationContext

2.1. AnnotationConfigApplicationContext Constructor

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
    // Call the no-argument constructor.
    this();
    // Register the main configuration class.
    register(annotatedClasses);
    // Refresh the IoC container.
    refresh();
}

The refresh method refreshes the container. This is the focus of our analysis. It calls the refresh method of AnnotationConfigApplicationContext’s parent class, AbstractApplicationContext.

2.2. Refresh the IoC Container

  • AbstractApplicationContext.refresh
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
    // Prepare this context for refreshing.
    // Parse placeholder properties.
    prepareRefresh();

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

    // Prepare the bean factory for use in this context.
    // Initialize some properties for the Bean factory and add some BeanPostProcessors.
    prepareBeanFactory(beanFactory);

    try {
        // Allows post-processing of the bean factory in context subclasses.
        // Do some work after the Bean factory has been created.
        // This is left for subclasses to implement (template method).
        postProcessBeanFactory(beanFactory);

        // Invoke factory processors registered as beans in the context.
        // Call BeanFactoryPostProcessor.postProcessBeanFactory in priority order.
        invokeBeanFactoryPostProcessors(beanFactory);

        // Register bean processors that intercept bean creation.
        // Register all BeanPostProcessors with the Bean factory.
        registerBeanPostProcessors(beanFactory);

        // Initialize message source for this context.
        // Initialize internationalization-related Beans.
        initMessageSource();

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

        // Initialize other special beans in specific context subclasses.
        // Left for subclasses to implement (template method).
        onRefresh();

        // Check for listener beans and register them.
        // Register event listeners with the event dispatcher.
        registerListeners();

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

        // Last step: publish corresponding event.
        finishRefresh();
    }

    catch (BeansException ex) {
        if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization - " +
                    "cancelling refresh attempt: " + ex);
        }

        // Destroy already
        destroyBeans();

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

        // Propagate exception to caller.
        throw ex;
    }

    finally {
        // Reset common introspection caches in Spring's core, since we
        // might not ever need metadata for singleton beans anymore...
        resetCommonCaches();
    }
}
}

2.2.1. Prepare for Refresh

  • AbstractApplicationContext.prepareRefresh
protected void prepareRefresh() {
    // Startup time and active flag.
    this.startupDate = System.currentTimeMillis();
    this.closed.set(false);
    this.active.set(true);

    if (logger.isInfoEnabled()) {
        logger.info("Refreshing " + this);
    }

    // Initialize any placeholder property sources in the context environment.
    // Initialize placeholder properties. Template method (left for subclasses to implement).
    initPropertySources();

    // Validate that all properties marked as required are resolvable:
    // see ConfigurablePropertyResolver#setRequiredProperties
    // Validate properties.
    getEnvironment().validateRequiredProperties();

    // Allow for the collection of early ApplicationEvents,
    // to be published once the multicaster is available...
    // Save early events. They are used later for event dispatch.
    this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}

There is not much to say about the preparation work; it is as described in the comments. The initPropertySources operation for initializing placeholder properties is left for subclasses to implement.

2.2.2. Obtain the Refreshed BeanFactory

  • AbstractApplicationContext.obtainFreshBeanFactory
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    // Refresh the Bean factory. Template method (left for subclasses to implement).
    refreshBeanFactory();
    // Obtain the Bean factory and return it -- when was it created?
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (logger.isDebugEnabled()) {
        logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
    }
    return beanFactory;
}

The refreshBeanFactory operation that refreshes the BeanFactory is again left for subclasses to implement.

2.2.3. Prepare BeanFactory

  • AbstractApplicationContext.prepareBeanFactory
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // Tell the internal bean factory to use the context's class loader etc.
    // Set the class loader and other properties.
    beanFactory.setBeanClassLoader(getClassLoader());
    beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

    // Configure the bean factory with context callbacks.
    // Add a PostProcessor to the Bean factory:
    // ApplicationContextAwareProcessor -> used for ApplicationContextAware,
    // and ignore some dependencies.
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
    beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
    beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
    beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

    // BeanFactory interface not registered as resolvable type in a plain factory.
    // MessageSource registered (and found for autowiring) as a bean.
    //
    beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
    beanFactory.registerResolvableDependency(ResourceLoader.class, this);
    beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
    beanFactory.registerResolvableDependency(ApplicationContext.class, this);

    // Register early post-processor for detecting inner beans as ApplicationListeners.
    // Add a PostProcessor to the Bean factory:
    // ApplicationListenerDetector -- used for event listeners.
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

    // Detect a LoadTimeWeaver and prepare for weaving, if found.
    // Add a PostProcessor to the Bean factory:
    // LoadTimeWeaverAwareProcessor -- used for aspects.
    if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        // Set a temporary ClassLoader for type matching.
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }

    // Register default environment beans.
    // Register environment-related Beans.
    if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
    }
}

This preparation mainly injects some PostProcessor instances into BeanFactory.

2.2.4. Call BeanFactoryPostProcessor’s postProcess Method

  • AbstractApplicationContext.invokeBeanFactoryPostProcessors
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    // Pass in the current Bean factory and all Bean-factory PostProcessors.
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

    // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
    // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
    if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }
}

This operation is important. See 2. Call BeanFactoryPostProcessor’s postProcess Method.

2.2.5. Register BeanPostProcessor

  • AbstractApplicationContext.registerBeanPostProcessors
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    // Pass in the current Bean factory.
    PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}

This operation is important. See 3. Register BeanPostProcessor.

  • initMessageSource
protected void initMessageSource() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    // Obtain messageSource from the Bean factory.
    if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
        this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
        // Make MessageSource aware of parent MessageSource.
        if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
            HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
            if (hms.getParentMessageSource() == null) {
                // Only set parent context as parent MessageSource if no parent MessageSource
                // registered already.
                hms.setParentMessageSource(getInternalParentMessageSource());
            }
        }
        if (logger.isDebugEnabled()) {
            logger.debug("Using MessageSource [" + this.messageSource + "]");
        }
    }
    // If it cannot be obtained:
    else {
        // Use empty MessageSource to be able to accept getMessage calls.
        // Create a default DelegatingMessageSource.
        DelegatingMessageSource dms = new DelegatingMessageSource();
        dms.setParentMessageSource(getInternalParentMessageSource());
        this.messageSource = dms;
        // Register it in the Bean factory.
        beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
        if (logger.isDebugEnabled()) {
            logger.debug("Unable to locate MessageSource with name '" + MESSAGE_SOURCE_BEAN_NAME +
                    "': using default [" + this.messageSource + "]");
        }
    }
}

2.2.7. Initialize the Event Dispatcher

  • initApplicationEventMulticaster
protected void initApplicationEventMulticaster() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    // Obtain the Bean named applicationEventMulticaster (the event dispatcher)
    // from the Bean factory.
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        this.applicationEventMulticaster =
                beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
        if (logger.isDebugEnabled()) {
            logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
        }
    }
    // If it cannot be obtained:
    else {
        // Create a SimpleApplicationEventMulticaster and register it with the Bean factory.
        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
        if (logger.isDebugEnabled()) {
            logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
                    APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
                    "': using default [" + this.applicationEventMulticaster + "]");
        }
    }
}

2.2.8. Register Event Listeners with the Event Dispatcher

  • registerListeners
protected void registerListeners() {
    // Register statically specified listeners first.
    // Obtain all event listeners and put them into the event dispatcher.
    for (ApplicationListener<?> listener : getApplicationListeners()) {
        getApplicationEventMulticaster().addApplicationListener(listener);
    }

    // Do not initialize FactoryBeans here: We need to leave all regular beans
    // uninitialized to let post-processors apply to them!
    // Obtain all Beans of type ApplicationListener from the Bean factory
    // and put them into the event dispatcher.
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    for (String listenerBeanName : listenerBeanNames) {
        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    }

    // Publish early application events now that we finally have a multicaster...
    // Obtain early events and dispatch them through the event dispatcher.
    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    this.earlyApplicationEvents = null;
    if (earlyEventsToProcess != null) {
        for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            getApplicationEventMulticaster().multicastEvent(earlyEvent);
        }
    }
}

2.2.9. Finish BeanFactory Initialization

  • finishBeanFactoryInitialization
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // Initialize conversion service for this context.
    if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
            beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
        beanFactory.setConversionService(
                beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
    }

    // Register a default embedded value resolver if no bean post-processor
    // (such as a PropertyPlaceholderConfigurer bean) registered any before:
    // at this point, primarily for resolution in annotation attribute values.
    if (!beanFactory.hasEmbeddedValueResolver()) {
        beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
            @Override
            public String resolveStringValue(String strVal) {
                return getEnvironment().resolvePlaceholders(strVal);
            }
        });
    }

    // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
    String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
    for (String weaverAwareName : weaverAwareNames) {
        getBean(weaverAwareName);
    }

    // Stop using the temporary ClassLoader for type matching.
    beanFactory.setTempClassLoader(null);

    // Allow for caching all bean definition metadata, not expecting further changes.
    beanFactory.freezeConfiguration();

    // Instantiate all remaining (non-lazy-init) singletons.
    // Instantiate all remaining non-lazy singleton Beans.
    beanFactory.preInstantiateSingletons();
}

This step is especially important. Its preInstantiateSingletons method instantiates all non-lazy singleton Beans. See 4. Instantiate All Non-Lazy Singleton Beans.

2.2.10. Finish the Refresh

  • finishRefresh
protected void finishRefresh() {
    // Initialize lifecycle processor for this context.
    // Initialize the lifecycle-related PostProcessor.
    initLifecycleProcessor();

    // Propagate refresh to lifecycle processor first.
    // Call onRefresh on the LifecycleProcessor just created.
    getLifecycleProcessor().onRefresh();

    // Publish the final event.
    // Publish the ContextRefreshedEvent event.
    publishEvent(new ContextRefreshedEvent(this));

    // Participate in LiveBeansView MBean, if active.
    LiveBeansView.registerApplicationContext(this);
}
  • initLifecycleProcessor
protected void initLifecycleProcessor() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    // Obtain LifecycleProcessor.
    if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
        this.lifecycleProcessor =
                beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
        if (logger.isDebugEnabled()) {
            logger.debug("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");
        }
    }
    // If it does not exist, create a default one and register it in the IoC container.
    else {
        DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
        defaultProcessor.setBeanFactory(beanFactory);
        this.lifecycleProcessor = defaultProcessor;
        beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
        if (logger.isDebugEnabled()) {
            logger.debug("Unable to locate LifecycleProcessor with name '" +
                    LIFECYCLE_PROCESSOR_BEAN_NAME +
                    "': using default [" + this.lifecycleProcessor + "]");
        }
    }
}

Discussion

Sign in with GitHub to comment. Discussions are stored as GitHub Issues.View on GitHub