1. ApplicationContextInitializer interface

/**
 * Callback interface for initializing a Spring {@link ConfigurableApplicationContext}
 * prior to being {@linkplain ConfigurableApplicationContext#refresh() refreshed}.
 *
 * <p>Typically used within web applications that require some programmatic initialization
 * of the application context. For example, registering property sources or activating
 * profiles against the {@linkplain ConfigurableApplicationContext#getEnvironment()
 * context's environment}. See {@code ContextLoader} and {@code FrameworkServlet} support * for declaring a "contextInitializerClasses" context-param and init-param, respectively. * * 

{@code ApplicationContextInitializer} processors are encouraged to detect * whether Spring'

s {@link org.springframework.core.Ordered Ordered} interface has been * implemented or if the @{@link org.springframework.core.annotation.Order Order} * annotation is present and to sort instances accordingly ifSo the prior to the invocation. * * @ author Chris Beams * @ since 3.1 * @ see org. Springframework. Web. Context. ContextLoader#customizeContext * @see org.springframework.web.context.ContextLoader#CONTEXT_INITIALIZER_CLASSES_PARAM * @see org.springframework.web.servlet.FrameworkServlet#setContextInitializerClasses * @see org.springframework.web.servlet.FrameworkServlet#applyInitializers*/ public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> { /** * Initialize the given application context. * @param applicationContext the application to configure */ void initialize(C applicationContext); }Copy the code

This is a Spring interface that automatically loads the implementation class and executes the Initialize method. In addition to implementing this interface, need on the web. In the XML configuration a < context – param > parameters, must be contextInitializerClasses < param – name >.

<context-param>
	<param-name>contextInitializerClasses</param-name>
	<param-value>com.xxx.XXXApplicationContextInitializer</param-value>
</context-param>Copy the code

So how does that process work?


So I wrote a demo to start debugging:

public class MySimpleContextListener implements ApplicationContextInitializer<ConfigurableApplicationContext> {

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("It's loading."); }}Copy the code



This is the call stack, from the bottom up, which is the order in which the code is executed.

Tomcat must be started first, then BLA… Bla… Bla… Boom… da… da… Da (skip the startup process I don’t understand).

After Tomcat is started, start the Web program and load it in sequence according to the Java Web startup sequence as follows:

ServletContext -> context-param -> listener -> filter -> servlet

A typical Web application built with springMVC will set this listener in web.xml

<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>Copy the code

Is the call stack in the ContextLoaderListener class, the class and inheritance org. Springframework. Web. Context. ContextLoader. In the call ContextLoaderListener class contextInitialized () method, and will call his father class initWebApplicationContext () method, as follows:

public void contextInitialized(ServletContextEvent event) {
	initWebApplicationContext(event.getServletContext());
}Copy the code

And then this method calls other methods, layer by layer, or whatever the order is in the call stack.

Finally, look at the ContextLoader class’s customizeContext() method:

    protected void customizeContext(ServletContext sc, ConfigurableWebApplicationContext wac) {
        List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>> initializerClasses =
                determineContextInitializerClasses(sc);

        for(Class<ApplicationContextInitializer<ConfigurableApplicationContext>> initializerClass : initializerClasses) { Class<? > initializerContextClass = GenericTypeResolver.resolveTypeArgument(initializerClass, ApplicationContextInitializer.class);if(initializerContextClass ! = null && ! initializerContextClass.isInstance(wac)) { throw new ApplicationContextException(String.format("Could not apply context initializer [%s] since its generic parameter [%s] " +
                                "is not assignable from the type of application context used by this " +
                                "context loader: [%s]", initializerClass.getName(), initializerContextClass.getName(),
                        wac.getClass().getName()));
            }
            this.contextInitializers.add(BeanUtils.instantiateClass(initializerClass));
        }

        AnnotationAwareOrderComparator.sort(this.contextInitializers);
        for(ApplicationContextInitializer<ConfigurableApplicationContext> initializer : this.contextInitializers) { initializer.initialize(wac); }}Copy the code


It’s all in here. Now you can read it line by line.

List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>> initializerClasses = determineContextInitializerClasses(sc);

Extract in its role from web. XML is called “globalInitializerClasses” and “contextInitializerClasses” < context – param > the value of the parameter. These values are strings in web.xml, so you need to convert them to Class<? > object, in the process of the transformation will check, the configuration of this is the name of the class implements ApplicationContextInitializer interface class, isn’t it throws an exception.

Then a for loop is check the configuration of these generic implementation class, whether ConfigurableApplicationContext. If not, an exception is thrown. If it is, it will be instantiated into an object and put into a List.

Finally, the for loop execution List ApplicationContextInitializer interface object, the initialize () method.


// How important it is to speak Good English…


2. The BeanPostProcessor interface

The purpose of this interface is to perform some operations before or after the initialization of the bean.

To make this work, you must put objects from the BeanPostProcessor interface implementation class into the container. There are two ways to add beans to the container: XML; Second, notes.

Roughly logically, Spring saves a List<BeanPostProcessor> object, and when the bean is initialized, for loops through the List, calling it in turn.

The logic is simple, but how does Spring put objects from the BeanPostProcessor interface implementation class into the container?

Above ApplicationContextInitializer interface through the web. The XML configuration, its implementation class is initialized before the container startup. The BeanPostProcessor interface, on the other hand, goes through almost the entire spring container startup process from load to effect.

Therefore, to understand how the BeanPostProcessor interface is loaded, you must understand how the Spring container is loaded.

Starting and loading the Spring container is a fairly tedious process, and documenting it requires starting a new blog, looking up resources, and then digging deeper into the source code. Here is only a cursory overview of the call stack in effect for the BeanPostProcessor interface.



Compared with ApplicationContextInitializer interface, this call process, significantly longer. Opening call is still the same, of course from org. Springframework. Web. Context. The ContextLoaderListener enter, initialize WebApplicationContext, then refresh, Here is part of the source code for the refresh method:

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); 		

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

The refresh method, and the methods called within the refresh method, and the methods called within the methods called, and the methods called within the methods called, comprise the loading process.

// This is not what I want to say, the source is far more convoluted than I said.

The process I’ve seen so far focuses on reading Spring configuration files (that is, XML). To handle, depending on the type of label and packaging into org. Springframework. Beans. Factory. Config. BeanDefinition, Finally in the org. Springframework. Beans. Factory. Support. DefaultListableBeanFactory# beanDefinitionMap.

Details of the new blog.


3.PropertyPlaceholderConfigurer

As with the BeanPostProcessor interface, the logic to invoke is simple, but the logic to load is difficult. It is also important to understand how the Spring container is loaded.



As shown in figure, invokeBeanFactoryPostProcessors method, it is within the refresh method call