Spring source code analysis II: context component (webapplicationcontext)

Time:2022-5-14

Spring source code analysis II: context component (webapplicationcontext)

The last article analyzedDispatcherServletAndContextLoaderListenerThese two classes resolve the process of application initialization and request processing, but some components need to be resolved:

  • ConfigurableWebApplicationContext.refreshRefresh context
  • ApplicationContext.getBeanGet bean from context
  • DispatcherServlet.propertiesPolicy processing defined in the file
  • ContextLoader.propertiesPolicy processing defined in the file
  • View.renderView rendering

Let’s take a look at this chapterContextLoader.propertiesPolicy processing defined in the file

ContextLoader.propertiesOnly one policy is defined in the file

org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

Default useXmlWebApplicationContext(loaded based on XML) as application context

spring-webFive application context classes are defined internally:

  • GenericWebApplicationContext
    WebApplicationContextBut it cannot load application configuration and beans through configuration files and annotations. It is generally used for extension implementation (such as springboot), and is rarely used directly
  • StaticWebApplicationContext
    : YesWebApplicationContextBut it does not support I18N. It is mainly used for testing without using the product environment
  • XmlWebApplicationContext
    : loading application configuration and bean based on XMLWebApplicationContextImplementation, which is the default context of spring MVC
  • AnnotationConfigWebApplicationContext
    For example, based on annotation:@Configuration, @beanLoading application configuration and beanWebApplicationContextrealization
  • GroovyWebApplicationContext
    : andXmlWebApplicationContextThe implementation of is almost the same, but groovy can be used to replace XML as the configuration file, which is not used much at present

Let’s take a look at the inheritance relationship of these five application context classes

- DefaultResourceLoader
  - AbstractApplicationContext
    - GenericApplicationContext
      - GenericWebApplicationContext

- DefaultResourceLoader
  - AbstractApplicationContext
    - GenericApplicationContext
      - StaticApplicationContext
        - StaticWebApplicationContext

- DefaultResourceLoader
  - AbstractApplicationContext
    - AbstractRefreshableApplicationContext
      - AbstractRefreshableConfigApplicationContext
        - AbstractRefreshableWebApplicationContext
          - XmlWebApplicationContext

- DefaultResourceLoader
  - AbstractApplicationContext
    - AbstractRefreshableApplicationContext
      - AbstractRefreshableConfigApplicationContext
        - AbstractRefreshableWebApplicationContext
          - AnnotationConfigWebApplicationContext

- DefaultResourceLoader
  - AbstractApplicationContext
    - AbstractRefreshableApplicationContext
      - AbstractRefreshableConfigApplicationContext
        - AbstractRefreshableWebApplicationContext
          - GroovyWebApplicationContext

We can find that each class inheritsAbstractApplicationContext, andXmlWebApplicationContext, AnnotationConfigWebApplicationContext,
GroovyWebApplicationContextAll inheritAbstractRefreshableWebApplicationContext

1. DefaultResourceLoader

DefaultResourceLoader
The main function of is to load resources

public class DefaultResourceLoader implements ResourceLoader {}

Let’s look at the interface firstResourceLoader

public interface ResourceLoader {
    //Obtain resources according to a character position information
    Resource getResource(String location);

    //Get resource loader
    ClassLoader getClassLoader();
}

DefaultResourceLoader
yesResourceLoaderDefault implementation of

public class DefaultResourceLoader implements ResourceLoader {
    @Override
    public ClassLoader getClassLoader() {
        //If there is a specified classloader, the specified is returned; if there is no classloader, the default is returned
        return (this.classLoader != null ? this.classLoader : ClassUtils.getDefaultClassLoader());
    }

    @Override
    public Resource getResource(String location) {
        //Custom protocol resolution
        for (ProtocolResolver protocolResolver : getProtocolResolvers()) {
            Resource resource = protocolResolver.resolve(location, this);
            if (resource != null) {
                return resource;
            }
        }

        //If it starts with /, it is considered a classpath resource
        if (location.startsWith("/")) {
            return getResourceByPath(location);
        }
        //If the classpath resource starting with classpath:
        else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
            return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
        }
        else {
            try {
                //Try to treat as a file or URL
                URL url = new URL(location);
                return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
            }
            catch (MalformedURLException ex) {
                //If it fails, the default is the classpath resource
                return getResourceByPath(location);
            }
        }
    }
}

2. AbstractApplicationContext

AbstractApplicationContext
Its main function is to obtain bean instances by name, type or annotation, obtain context environment objects and resources, and refresh context data

public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext {}

InterfaceConfigurableApplicationContext
And its inherited interfaces mainly define the following methods

public interface ConfigurableApplicationContext {
    //Get bean
    Object getBean(String name) throws BeansException;
    <T> T getBean(String name, Class<T> requiredType) throws BeansException;
    Object getBean(String name, Object... args) throws BeansException;
    <T> T getBean(Class<T> requiredType) throws BeansException;
    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

    //Get beans by type or annotation
    <T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException;
    <T> Map<String, T> getBeansOfType(@Nullable Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)
            throws BeansException;
    Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException;

    //Get environment
     ConfigurableEnvironment getEnvironment();

    //Refresh context data
    void refresh() throws BeansException, IllegalStateException;

    //Obtain multiple resources according to locationpattern, such as wildcards*
    Resource[] getResources(String locationPattern) throws IOException;
}

2.1. AbstractApplicationContext.getEnvironment

AbstractApplicationContext.getEnvironment
Get environment

public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext {
    @Override
    public ConfigurableEnvironment getEnvironment() {
        if (this.environment == null) {
            this.environment = createEnvironment();
        }
        return this.environment;
    }

    protected ConfigurableEnvironment createEnvironment() {
        //Built in standard environment (you can also customize the environment processing mechanism through setenvironment method)
        //You can use ` application-dev.yml, application test yml, application-prod.yml, ...`  To load the underlying implementation of different configurations according to the environment
        //Spring boot is the basic function of spring boot
        return new StandardEnvironment();
    }
}

2.2. AbstractApplicationContext.getBean

AbstractApplicationContext.getBean
Get bean

public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext {
    @Override
    public Object getBean(String name) throws BeansException {
        return getBeanFactory().getBean(name);
    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return getBeanFactory().getBean(name, requiredType);
    }

    @Override
    public Object getBean(String name, Object... args) throws BeansException {
        return getBeanFactory().getBean(name, args);
    }

    @Override
    public <T> T getBean(Class<T> requiredType) throws BeansException {
        return getBeanFactory().getBean(requiredType);
    }

    @Override
    public <T> T getBean(Class<T> requiredType, Object... args) throws BeansException {
        return getBeanFactory().getBean(requiredType, args);
    }

    //Left to subclass implementation
    public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}

Because differentContextThe way to register beans is different, sogetBeanFactoryLeave it to subclasses to implement

2.3. AbstractApplicationContext.getBeansOfType

AbstractApplicationContext.getBeansOfType
Get beans by type or annotation

public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext {
    @Override
    public <T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException {
        return getBeanFactory().getBeansOfType(type);
    }

    @Override
    public <T> Map<String, T> getBeansOfType(@Nullable Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)
            throws BeansException {
        return getBeanFactory().getBeansOfType(type, includeNonSingletons, allowEagerInit);
    }

    @Override
    public Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType)
            throws BeansException {
        return getBeanFactory().getBeansWithAnnotation(annotationType);
    }

    //Left to subclass implementation
    public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}

2.4. AbstractApplicationContext.refresh

AbstractApplicationContext.refresh
Refresh context data

public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext {
    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // ...  Code omission

            //Initialize the event container and listener, check the necessary property configuration, and load the necessary instances
            prepareRefresh();

            //Refresh the bean of the context and get the bean factory
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            //Prepare bean factory
            prepareBeanFactory(beanFactory);

            try {
                //Post processing bean factory
                postProcessBeanFactory(beanFactory);

                // ...  Code omission

                //Call the post processor of the bean factory so that you can add your own beanpostprocessor (post operation of bean instantiation) before all beans are instantiated
                invokeBeanFactoryPostProcessors(beanFactory);

                //Register beanpostprocessor for bean factory (bean instantiation post operation)
                registerBeanPostProcessors(beanFactory);

                // ...  Code omission

                //Instantiate the applicationeventmulticast bean as an application event broadcaster
                initApplicationEventMulticaster();

                //Extension implementation, left to developers, not implemented by default
                onRefresh();

                //Register application event listener
                registerListeners();

                //Initialize all singleton beans
                finishBeanFactoryInitialization(beanFactory);

                //After refreshing the context data, do some subsequent processing
                finishRefresh();
            }

            catch (BeansException ex) {
                // ...  Code omission
            }

            finally {
                // ...  Code omission
            }
        }
    }

    //Refresh the bean of the context and get the bean factory
    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        //Refresh context bean
        refreshBeanFactory();
        //Get bean factory
        return getBeanFactory();
    }

    //Refresh context bean,由子类实现
    protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;

    //Get bean factory,由子类实现
    public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;

    //Extension implementation, left to developers, not implemented by default
    protected void onRefresh() throws BeansException {}

    //Initialize all singleton beans
    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        // ...  Code omission

        //Solidify the configuration of all beans and will not be changed later
        beanFactory.freezeConfiguration();

        //Initialize all singleton beans
        beanFactory.preInstantiateSingletons();
    }

    //After refreshing the context data, do some subsequent processing
    protected void finishRefresh() {
        //Clear some resource caches
        clearResourceCaches();

        //Instantiate lifecycle processor bean
        initLifecycleProcessor();

        //Instantiate lifecycle beans and call the start method of these beans
        getLifecycleProcessor().onRefresh();

        //Dispatch event
        publishEvent(new ContextRefreshedEvent(this));

        // ...  Code omission
    }
}
  • Because differentContextThe way to register beans is different, sorefreshBeanFactory, postProcessBeanFactoryLeave it to subclasses to implement
  • ConfigurableListableBeanFactoryHow to load and instantiate beans and parse later

2.5. AbstractApplicationContext.prepareBeanFactory

AbstractApplicationContext.prepareBeanFactory
Prepare bean factory

public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext {
    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // ...  Code omission

        //Add support for #{} spiel spring expression language
        if (!shouldIgnoreSpel) {
            beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        }

        //Adding an attribute editor to convert the values defined in XML and yaml into objects depends on this implementation
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

        //Add a beanpostprocessor and a post processor
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

        // ...  Code omission

        //Register several instances that can be loaded automatically by autowireable
        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);

        // ...  Code omission

        //Register several singleton 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());
        }
        if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
            beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
        }
    }
}
  • ResourceEditorRegistrarHow to register the Attribute Editor and how to resolve the attribute editor into an object, which will be resolved later

2.6. AbstractApplicationContext.getResources

AbstractApplicationContext.getResources
Obtain multiple resources according to locationpattern, such as wildcards*

public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext {
    private ResourcePatternResolver resourcePatternResolver;

    public AbstractApplicationContext() {
        this.resourcePatternResolver = getResourcePatternResolver();
    }

    protected ResourcePatternResolver getResourcePatternResolver() {
        return new PathMatchingResourcePatternResolver(this);
    }

    @Override
    public Resource[] getResources(String locationPattern) throws IOException {
        return this.resourcePatternResolver.getResources(locationPattern);
    }
}
  • PathMatchingResourcePatternResolverHow to parse and load the resources specified by locationpattern, and then parse later

2.7. overview

in general,AbstractApplicationContextClass completes most of the functions of the context environment, including environment loading, bean loading, pre and post processing, event dispatching, completing some initialization, etc,
However, several interfaces are extended to subclass implementation, such as how to load, register and instantiate beans

3. GenericApplicationContext

GenericApplicationContext
Its main function is to register and manage bean definitions and aliases

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {}

BeanDefinitionRegistry
This interface mainly defines the definition and alias of registered beans

public interface BeanDefinitionRegistry {
    //Register bean definitions
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException;

    //Delete bean definition
    void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    //Get bean definition
    BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    //Check bean definition
    boolean containsBeanDefinition(String beanName);

    //Register bean alias
    void registerAlias(String name, String alias);

    //Delete bean alias
    void removeAlias(String alias);

    //Check bean alias
    boolean isAlias(String name);

    //Get bean alias
    String[] getAliases(String name);
}

Let’s seeGenericApplicationContextHow to implement these interfaces

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {

        this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
    }

    @Override
    public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
        this.beanFactory.removeBeanDefinition(beanName);
    }

    @Override
    public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
        return this.beanFactory.getBeanDefinition(beanName);
    }

    @Override
    public void registerAlias(String beanName, String alias) {
        this.beanFactory.registerAlias(beanName, alias);
    }

    @Override
    public void removeAlias(String alias) {
        this.beanFactory.removeAlias(alias);
    }

    @Override
    public boolean isAlias(String beanName) {
        return this.beanFactory.isAlias(beanName);
    }
}

Finally settled inbeanFactoryupper

4. GenericWebApplicationContext

GenericWebApplicationContext
The main function of is to add the source of setting bean configuration file, which allows the instantiation of context environment through configuration

public class GenericWebApplicationContext extends GenericApplicationContext
        implements ConfigurableWebApplicationContext, ThemeSource {}

ConfigurableWebApplicationContext

public interface ConfigurableWebApplicationContext {
    //Set bean configuration file source
    void setConfigLocation(String configLocation);
    //Set multiple bean profile sources
    void setConfigLocations(String... configLocations);
    //Get bean configuration file source
    String[] getConfigLocations();
}

ConfigurableWebApplicationContextExpandedWebApplicationContext, which defines the context that can be instantiated by configuration

public class GenericWebApplicationContext extends GenericApplicationContext
        implements ConfigurableWebApplicationContext, ThemeSource {
    @Override
    protected ConfigurableEnvironment createEnvironment() {
        //The standardservlet environment extends the standardenvironment
        //Added that application configuration sources can be added from servlet context init parameters and servlet config init parameters
        return new StandardServletEnvironment();
    }

    //Bean configuration file source cannot be set
    @Override
    public void setConfigLocation(String configLocation) {
        if (StringUtils.hasText(configLocation)) {
            throw new UnsupportedOperationException(
                    "GenericWebApplicationContext does not support setConfigLocation(). " +
                    "Do you still have an 'contextConfigLocations' init-param set?");
        }
    }

    @Override
    public void setConfigLocations(String... configLocations) {
        if (!ObjectUtils.isEmpty(configLocations)) {
            throw new UnsupportedOperationException(
                    "GenericWebApplicationContext does not support setConfigLocations(). " +
                    "Do you still have an 'contextConfigLocations' init-param set?");
        }
    }

    @Override
    public String[] getConfigLocations() {
        throw new UnsupportedOperationException(
                "GenericWebApplicationContext does not support getConfigLocations()");
    }
}

GenericWebApplicationContextNot achievedConfigurableWebApplicationContextThe core method of can’t load the configuration through the file,
The purpose of this kind of design is not toweb.xmlFor declarative installation, but programmatic installation, such as usingWebApplicationInitializersTo construct the embedded context; It is rarely used

5. StaticWebApplicationContext

becauseStaticApplicationContext
There are few functions to be realized, which can be analyzed here

public class StaticApplicationContext extends GenericApplicationContext {
    private final StaticMessageSource staticMessageSource;

    public StaticApplicationContext(@Nullable ApplicationContext parent) throws BeansException {
        super(parent);

        //There is a MessageSource component in the context object, which implements the I18N function
        //The staticmessagesource realizes that the program loads text instead of files, which removes the I18N function
        this.staticMessageSource = new StaticMessageSource();
        getBeanFactory().registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.staticMessageSource);
    }
}

StaticWebApplicationContext
There are few functions

public class StaticWebApplicationContext extends StaticApplicationContext
        implements ConfigurableWebApplicationContext, ThemeSource {
    //Bean configuration file source cannot be set
    @Override
    public void setConfigLocation(String configLocation) {
        throw new UnsupportedOperationException("StaticWebApplicationContext does not support config locations");
    }

    @Override
    public void setConfigLocations(String... configLocations) {
        throw new UnsupportedOperationException("StaticWebApplicationContext does not support config locations");
    }

    @Override
    public String[] getConfigLocations() {
        return null;
    }
}

StaticWebApplicationContextNor has it been achievedConfigurableWebApplicationContextThe core method of can’t load the configuration through the file,
This kind of design is mainly used for testing, not for product environment

6. AbstractRefreshableApplicationContext

AbstractRefreshableApplicationContext
The main function of is to create a bean factory and refresh the context data

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
    @Override
    protected final void refreshBeanFactory() throws BeansException {
        // ...  Code omission
        try {
            //Create bean factory
            DefaultListableBeanFactory beanFactory = createBeanFactory();

            // ...  Code omission

            //Load bean definition
            loadBeanDefinitions(beanFactory);
            this.beanFactory = beanFactory;
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }

    //Create bean factory
    protected DefaultListableBeanFactory createBeanFactory() {
        //By default, the defaultlistablebeanfactory is used to create a bean factory
        return new DefaultListableBeanFactory(getInternalParentBeanFactory());
    }

    //Load bean definition,由子类实现
    protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
                throws BeansException, IOException;
}

7. AbstractRefreshableConfigApplicationContext

AbstractRefreshableConfigApplicationContext
The main function of is that the configuration can be loaded through files

public abstract class AbstractRefreshableConfigApplicationContext extends AbstractRefreshableApplicationContext
        implements BeanNameAware, InitializingBean {
    //Set the source of configuration file to separate multiple with ",; \ t \ n"
    public void setConfigLocation(String location) {
        setConfigLocations(StringUtils.tokenizeToStringArray(location, CONFIG_LOCATION_DELIMITERS));
    }

    public void setConfigLocations(@Nullable String... locations) {
        if (locations != null) {
            this.configLocations = new String[locations.length];
            for (int i = 0; i < locations.length; i++) {
                //Resolve the path and replace the ${} placeholder
                this.configLocations[i] = resolvePath(locations[i]).trim();
            }
        }
        else {
            this.configLocations = null;
        }
    }

    //Gets the source set of the configuration file. If not, the default is returned
    protected String[] getConfigLocations() {
        return (this.configLocations != null ? this.configLocations : getDefaultConfigLocations());
    }

    //The default profile source set is implemented by subclasses
    protected String[] getDefaultConfigLocations() {
        return null;
    }

    //Resolve the path and replace the ${} placeholder,有PropertySourcesPropertyResolver.resolveRequiredPlaceholders实现此功能
    protected String resolvePath(String path) {
        return getEnvironment().resolveRequiredPlaceholders(path);
    }
}
  • AbstractRefreshableConfigApplicationContextRealizedConfigurableWebApplicationContextThe core method is to load configuration files
  • PropertySourcesPropertyResolverHow to resolve the path? We will resolve it later

8. XmlWebApplicationContext

becauseAbstractRefreshableWebApplicationContext
There are few functions to be realized, which can be analyzed here

public abstract class AbstractRefreshableWebApplicationContext extends AbstractRefreshableConfigApplicationContext
        implements ConfigurableWebApplicationContext, ThemeSource {
    @Override
    protected ConfigurableEnvironment createEnvironment() {
        //The standardservlet environment extends the standardenvironment
        //Added that application configuration sources can be added from servlet context init parameters and servlet config init parameters
        return new StandardServletEnvironment();
    }
}

XmlWebApplicationContext
The main function of is to define the default configuration file, create an XML parser of bean definition, and register bean definition

public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {
    //Default profile
    public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";

    //Default profile前缀
    public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";

    //Default profile后缀
    public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";

    @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        //Create a bean defined XML parser and implement it with xmlbeandefinitionreader
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        // ...  Code omission

        //Load bean definition
        loadBeanDefinitions(beanDefinitionReader);
    }

    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            for (String configLocation : configLocations) {
                //Load bean definition through configuration file
                reader.loadBeanDefinitions(configLocation);
            }
        }
    }

    @Override
    protected String[] getDefaultConfigLocations() {
        if (getNamespace() != null) {
            //If there is servlet name (such as testapp), wrap it with prefix and suffix as "/ WEB-INF / testapp servlet. XML"
            return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};
        }
        else {
            //If not, the default is "/ WEB-INF / ApplicationContext. XML" file
            return new String[] {DEFAULT_CONFIG_LOCATION};
        }
    }
}

XmlWebApplicationContextIt mainly solves two problems:

  1. The default configuration file is defined, including servlet name (such astestapp), wrapped with prefix and suffix/WEB-INF/testapp-servlet.xml, if there is no servlet name; otherwise/WEB-INF/applicationContext.xml
  2. Create an XML parser of bean definition and load the bean definition through the configuration file

The default loading mechanism of spring MVC framework is to useXmlWebApplicationContextAs a context, fromxmlFile loading configuration and bean definition

as forXmlBeanDefinitionReaderHow to parse the bean definition, and then parse it later

9. AnnotationConfigWebApplicationContext

AnnotationConfigWebApplicationContext
Its main function is to load configuration and bean definitions through annotations

public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWebApplicationContext
        implements AnnotationConfigRegistry {}

Let’s see firstAnnotationConfigRegistry

public interface AnnotationConfigRegistry {
    //Register components by class name
    void register(Class<?>... componentClasses);

    //Scan components by package name
    void scan(String... basePackages);
}

These two methods happen to be annotated, such as@Configuration, @bean, @Component, @Controller, @ServiceThe underlying mechanism of registering beans

Let’s seeAnnotationConfigWebApplicationContextHow is it achieved

public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWebApplicationContext
        implements AnnotationConfigRegistry {
    //Component class collection
    private final Set<Class<?>> componentClasses = new LinkedHashSet<>();
    //Scan package name collection
    private final Set<String> basePackages = new LinkedHashSet<>();

    //Register components
    @Override
    public void register(Class<?>... componentClasses) {
        Collections.addAll(this.componentClasses, componentClasses);
    }

    //Add scan package name
    @Override
    public void scan(String... basePackages) {
        Collections.addAll(this.basePackages, basePackages);
    }

    //Load bean definition
    @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
        //Create a bean defined annotation parser and implement it with annotatedbeandefinitionreader
        AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
        //Create a bean annotation scanner based on package name and implement it with classpathbeandefinitionscanner
        ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);

        //Create a bean naming generator
        BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
        if (beanNameGenerator != null) {
            reader.setBeanNameGenerator(beanNameGenerator);
            scanner.setBeanNameGenerator(beanNameGenerator);
            beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
        }

        //Create a bean scope meta information parser to determine whether the registered bean is a prototype or a singleton
        ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
        if (scopeMetadataResolver != null) {
            reader.setScopeMetadataResolver(scopeMetadataResolver);
            scanner.setScopeMetadataResolver(scopeMetadataResolver);
        }

        //Register components类
        if (!this.componentClasses.isEmpty()) {
            reader.register(ClassUtils.toClassArray(this.componentClasses));
        }

        //Scan package
        if (!this.basePackages.isEmpty()) {
            scanner.scan(StringUtils.toStringArray(this.basePackages));
        }

        //Register component classes or scan package names through defined configuration sources
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            for (String configLocation : configLocations) {
                try {
                    Class<?> clazz = ClassUtils.forName(configLocation, getClassLoader());
                    reader.register(clazz);
                }
                catch (ClassNotFoundException ex) {
                    int count = scanner.scan(configLocation);
                    // ...  Code omission
                }
            }
        }
    }

    //Create a bean defined annotation parser and implement it with annotatedbeandefinitionreader
    protected AnnotatedBeanDefinitionReader getAnnotatedBeanDefinitionReader(DefaultListableBeanFactory beanFactory) {
        return new AnnotatedBeanDefinitionReader(beanFactory, getEnvironment());
    }

    //Create a bean annotation scanner based on package name and implement it with classpathbeandefinitionscanner
    protected ClassPathBeanDefinitionScanner getClassPathBeanDefinitionScanner(DefaultListableBeanFactory beanFactory) {
        return new ClassPathBeanDefinitionScanner(beanFactory, true, getEnvironment());
    }
}

In fact, registered beans are created byAnnotatedBeanDefinitionReaderDone, the scanning package isClassPathBeanDefinitionScannerAfter completion, these two classes will be parsed later

10. GroovyWebApplicationContext

GroovyWebApplicationContext
Operation mechanism andXmlWebApplicationContextAlmost, fromgroovyFile loading configuration and bean definition

public class GroovyWebApplicationContext extends AbstractRefreshableWebApplicationContext implements GroovyObject {
    //Default profile
    public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.groovy";

    //Default profile前缀
    public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";

    //Default profile后缀
    public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".groovy";

    @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        //Create a groovy parser defined by beans and implement it with groovybeandefinitionreader
        GroovyBeanDefinitionReader beanDefinitionReader = new GroovyBeanDefinitionReader(beanFactory);

        // ...  Code omission

        //Load bean definition
        loadBeanDefinitions(beanDefinitionReader);
    }

    protected void loadBeanDefinitions(GroovyBeanDefinitionReader reader) throws IOException {
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            for (String configLocation : configLocations) {
                //Load bean definition through configuration file
                reader.loadBeanDefinitions(configLocation);
            }
        }
    }

    @Override
    protected String[] getDefaultConfigLocations() {
        if (getNamespace() != null) {
            //If there is a servlet name (such as testapp), wrap it with the prefix and suffix "/ WEB-INF / testapp servlet. Groovy"
            return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};
        }
        else {
            //If not, the default is "/ WEB-INF / ApplicationContext. Groovy" file
            return new String[] {DEFAULT_CONFIG_LOCATION};
        }
    }
}

11. Overview

WebApplicationContext
The basic process of web application initialization is defined. There are mainly five implementation classes. The commonly used ones are: XML based loadingXmlWebApplicationContext
And annotation based loadingAnnotationConfigWebApplicationContext

  • GenericWebApplicationContextStaticWebApplicationContext
    : both are justWebApplicationContextThe basic implementation of can not load application configuration and beans through configuration files and annotations. It is generally used for extension implementation (such as springboot), and is rarely used directly
  • XmlWebApplicationContext
    : the context environment for loading application configurations and beans based on XML is the default context of spring MVC
  • AnnotationConfigWebApplicationContext
    For example, based on annotation:@Configuration, @beanBean loading environment and application context
  • GroovyWebApplicationContext
    : andXmlWebApplicationContextThe implementation of is almost the same, but groovy can be used to replace XML as the configuration file, but at present, groovy is far less popular than XML, and it is still not used much

12. Unfinished

There are still some points in this section to be resolved next time:

  • ConfigurableListableBeanFactoryHow to load and instantiate beans
  • ResourceEditorRegistrarHow to register the Attribute Editor and how the Attribute Editor resolves to an object
  • PathMatchingResourcePatternResolverHow to load the specified pattern
  • PropertySourcesPropertyResolverHow to resolve paths
  • XmlBeanDefinitionReaderHow to parse bean definitions
  • AnnotatedBeanDefinitionReaderHow do I register beans
  • ClassPathBeanDefinitionScannerHow are packages scanned

follow-up

More blogs, seehttps://github.com/senntyou/blogs

Author:Deep (@ senntyou)

Copyright notice: Free Reprint – non commercial – non derivative – keep signature(Creative sharing 3.0 License