The source code of Wanzi parsed XML configuration mapped to BeanDefinition

This article is shared from Huawei Cloud Community " Spring Master's Road 16 - Parsing XML Configuration Mapping into BeanDefinition Source Code ", author: Zhuan Yeyang__.

1. Analysis of BeanDefinition stage

SpringIOCThe specific steps of the control inversion ( ) container phase in the framework BeanDefinitionmainly involve Beandefinition, loading, parsing, and subsequent programmatic injection and post-processing. This phase is one of the early stages of the life cycle Springin the framework and is critical to understanding the entire framework.BeanSpring

  • Load configuration files and configuration classes

In this step, Springthe container uses configuration files or configuration classes to understand what needs to be managed Bean. For XMLconfiguration based on , typically use ClassPathXmlApplicationContexteither or FileSystemXmlApplicationContext.

  • Parse configuration files and configuration classes and encapsulate them as BeanDefinition

SpringThe framework parses configuration files by using BeanDefinitionReaderinstances such as XmlBeanDefinitionReaderAfter parsing, each Beanconfiguration will be encapsulated into an BeanDefinitionobject, which contains class name, scope, life cycle callback and other information.

  • Programmatically inject additional BeanDefinitions

In addition to what is defined in the configuration file , it can also be dynamically added to the container Beanprogrammatically , which increases flexibility.BeanDefinitionIOC

  • BeanDefinition post-processing

BeanDefinitionPost-processing means that the container allows the use of BeanDefinitionRegistryPostProcessoror to further process BeanFactoryPostProcessorthe parsed data , such as modified attributes, etc.BeanDefinitionBean

2. Load xml configuration file

2.1 Code example for loading beans in XML configuration file

First give the simplest code example, and then analyze it step by step

The entire code is as follows:

package com.example.demo.bean;

// HelloWorld.java
public class HelloWorld {
    private String message;

    public void setMessage(String message) {
        this.message = message;
    }

    public void sayHello() {
        System.out.println("Hello, " + message + "!");
    }
}

Main program:

package com.example.demo;

import com.example.demo.bean.HelloWorld;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DemoApplication {

    public static void main(String[] args) {
        //Create Spring context (container)
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("ApplicationContext.xml");

        // Get the bean from the container, assuming we have a bean named 'helloWorld'
        HelloWorld helloWorld = context.getBean("helloWorld", HelloWorld.class);

        // use bean
        helloWorld.sayHello();

        //Close context
        context.close();
    }
}

xml file

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- Bean definition-->
    <bean id="helloWorld" class="com.example.demo.bean.HelloWorld">
        <!-- Set properties -->
        <property name="message" value="World"/>
    </bean>

</beans>

operation result:

Then we will start analyzing this code

2.2 setConfigLocations - Set and save configuration file paths

Let’s take Spring 5.3.7the source code as an example to analyze

//Create Spring context (container)
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("ApplicationContext.xml");

ideaWe clicked to analyze this code , and finally saw the path to the configuration file ClassPathXmlApplicationContextbeing called in the overload method .setConfigLocations

Let’s see setConfigLocationshow

setConfigLocations() The main function of the method is to set the configuration file path that needs to be read when the container loads the definition. These paths can be resources on the classpath, resources in the file system, or any other resources that are located. This method ensures that all provided configuration paths are saved and used in later container refresh operations. Spring  Bean URL

The source code is brought up for analysis:

public void setConfigLocations(@Nullable String... locations) {
    if (locations != null) {
        // Use Spring's Assert class to verify that there are no null elements in the passed configuration location array.
        Assert.noNullElements(locations, "Config locations must not be null");
        
        // Initialize the array of internal storage configuration locations based on the number of configuration locations passed in.
        this.configLocations = new String[locations.length];

        // Traverse the passed configuration location array.
        for(int i = 0; i < locations.length; ++i) {
            // Call the resolvePath method to process each configuration location (possibly performing necessary path resolution, such as parsing placeholders).
            // trim() is used to remove spaces at the beginning and end of the string to ensure that the saved path is purified.
            this.configLocations[i] = this.resolvePath(locations[i]).trim();
        }
    } else {
        // If the configuration location passed in is null, clear all set configuration locations.
        this.configLocations = null;
    }
}

When the context is refreshed, these configuration file locations will be read, and Springthe container will resolve the definitions there beansand register them with the container. setConfigLocations() The method just sets these locations, and the actual loading and registration process is done when the context is refreshed.

This setConfigLocationsmethod is usually not called directly by the user, but ApplicationContextis called by the framework during the initialization process. For example, in the based XMLconfiguration, we will provide the path to the configuration file during initialization ClassPathXmlApplicationContextor .FileSystemXmlApplicationContext

At debugthis time, you can see that the path to the configuration file set in the test code is saved. xml 

2.3 refresh - Trigger container refresh, loading and parsing of configuration files

We saw above ClassPathXmlApplicationContextthat in the method, setConfigLocationsafter , there is a refreshmethod, let's take a look.

In Springthe framework, refresh()methods are very critical, they are ApplicationContextpart of the interface. The main functions of this method are to refresh the application context, load or reload those defined in the configuration file Bean, initialize all singletons, configure message resources, event publishers, etc.

The code is brought up for analysis:

public void refresh() throws BeansException, IllegalStateException {
    // Synchronized block to ensure thread safety of container refresh process
    synchronized(this.startupShutdownMonitor) {
        //Start recording the steps of context refresh for monitoring and diagnosis
        StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
        
        // Prepare the refresh process, set the start time, status flags, etc.
        this.prepareRefresh();
        
        // Get a new BeanFactory. If it is refreshed for the first time, create a BeanFactory.
        ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
        
        // Configure BeanFactory, register ignored dependent interfaces, etc.
        this.prepareBeanFactory(beanFactory);

        try {
            //Allow BeanFactory's post-processor to modify it
            this.postProcessBeanFactory(beanFactory);
            
            // Start monitoring the post-processing steps of the Bean factory
            StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
            
            //Call BeanFactoryPostProcessors
            this.invokeBeanFactoryPostProcessors(beanFactory);
            
            //Register BeanPostProcessors to BeanFactory
            this.registerBeanPostProcessors(beanFactory);
            
            //Bean post-processing step ends
            beanPostProcess.end();
            
            // Initialize the MessageSource component for internationalization and other functions
            this.initMessageSource();
            
            //Initialize event broadcaster
            this.initApplicationEventMulticaster();
            
            // Custom methods left to be overridden by subclasses
            this.onRefresh();
            
            //Register listener
            this.registerListeners();
            
            //Initialize remaining singleton beans
            this.finishBeanFactoryInitialization(beanFactory);
            
            // Complete the refresh process, notify the lifecycleProcessor of the refresh process, and publish the ContextRefreshedEvent event
            this.finishRefresh();
        } catch (BeansException var10) {
            //Catch BeansException, record warning information, and destroy created beans
            if (this.logger.isWarnEnabled()) {
                this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
            }

            // Destroy the initialized singleton Bean
            this.destroyBeans();
            
            //Cancel refresh and reset the flag on the sync monitor
            this.cancelRefresh(var10);
            
            //Throw an exception and end the refresh process
            throw var10;
        } finally {
            // At the end of the refresh, reset the shared cache in the Spring kernel
            this.resetCommonCaches();
            
            //End the recording of the context refresh step
            contextRefresh.end();
        }
    }
}

This method performs a precise sequence of steps to configure ApplicationContext, including Beanloading, registration, and initialization. The refresh process includes a series of complex steps such as Beandefinition loading, registration, and initialization.Bean

In modern Springframeworks, ApplicationContextit is generally refreshed once when the container starts. Once the container is started and the context is refreshed, everything Beanis loaded and created. Although it is technically possible to call refresh()a method multiple times, this is not common in practice as it would mean resetting the state of the application context and starting over. Doing so will destroy all singletons Beanand reinitialize them, which is not advisable in most applications. It is not only expensive but may also lead to problems such as state loss and data inconsistency.

For based on xml( ApplicationContextsuch as ClassPathXmlApplicationContext), refresh()the configuration file is re-read and parsed when the method is called, and the definitions of BeanFactoryand are re-created Bean. If the container has been refreshed, all singletons need to be destroyed Bean, closed BeanFactory, and then re-created. Usually, this feature is used during development or testing, and is not recommended for use in production environments because of its high overhead and risks.

Let’s take a look at the key points. Where is the operation of loading the configuration file? I marked it on the picture here, and obtainFreshBeanFactorythere is a method in the method refreshBeanFactory.

refreshBeanFactoryMethod is an abstract method. Let's take a look at how the implementation class is implemented and find refreshBeanFactorythe method to implement the class based on the inheritance relationship.

refreshBeanFactory()Methods refresh()are usually called within methods. This method ensures that the current ApplicationContextone contains a clean state BeanFactory.

The code is brought up for analysis:

protected final void refreshBeanFactory() throws BeansException {
    // Check whether the current application context already contains a BeanFactory
    if (this.hasBeanFactory()) {
        // If a BeanFactory already exists, destroy all beans managed by it
        this.destroyBeans();
        // Close the existing BeanFactory and release any resources it may hold
        this.closeBeanFactory();
    }

    try {
        // Create a new instance of DefaultListableBeanFactory, which is the default implementation of the ConfigurableListableBeanFactory interface in Spring
        DefaultListableBeanFactory beanFactory = this.createBeanFactory();
        //Set a serialization ID for the beanFactory. This ID can be used for deserialization later.
        beanFactory.setSerializationId(this.getId());
        // Allow subclasses to customize the newly created beanFactory
        this.customizeBeanFactory(beanFactory);
        //Load bean definitions from underlying resources (such as XML files) to beanFactory
        this.loadBeanDefinitions(beanFactory);
        //Assign the new beanFactory to the beanFactory property of this context
        this.beanFactory = beanFactory;
    } catch (IOException var2) {
        // If an I/O exception occurs during parsing the bean definition resource, wrap it and rethrow it as ApplicationContextException
        throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName() + "", var2);
    }
}

This method AbstractApplicationContextis overridden in the specific implementation. It provides beana template for refreshing the factory - if one already exists, destroy it and close it; then create a new beanfactory, customize it, and populate beanthe definitions. If an exception is encountered while loading beana definition (for example, reading from XMLa file), I/Oone is thrown ApplicationContextException, providing more contextual information about the nature of the error.

We can see in this code that there are loadBeanDefinitionsmethods to load definitions from underlying resources (such as XMLfiles) . The logic is very complicated. Let's analyze it separately below.beanbeanFactory

2.4 loadBeanDefinitions - specific BeanDefinition loading logic

this.loadBeanDefinitions Methods are implemented in subclasses. This pattern is a typical example of the template method design pattern . In the template method design pattern, the framework of an algorithm (i.e., a series of steps) is defined in the method of the parent class, but the specific implementation of some steps will be delayed to the subclass. AbstractApplicationContext 

AbstractApplicationContext Provides a framework of methods that define the refresh steps, but leaves its specific implementation to subclasses. Subclasses need to implement this method based on specific storage resource types (such as files, annotations, scripts, etc.). refreshBeanFactory  BeanFactory  loadBeanDefinitions  XML Java Groovy 

AbstractXmlApplicationContextThe methods implemented by subclasses loadBeanDefinitions are as follows:

cke_134.png

loadBeanDefinitions()Methods are the core methods Springin the framework for loading, parsing, and registering Beandefinitions. Its basic responsibility is to read configuration information from one or more sources and then convert this information into definitions Springthat the container can manage . BeanThis method is usually Springcalled during context initialization and is a key step in Springcontainer loading Beandefinition.

The code is brought up for analysis:

// Use DefaultListableBeanFactory as the target factory for Bean definition registration to load the Bean definition.
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    //Create a reader that reads the XML Bean definition and pass in the factory to register the definition
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    //Set the environment object, which may include environment configuration related to attribute resolution
    beanDefinitionReader.setEnvironment(this.getEnvironment());
    //Set the resource loader to allow the reader to load XML resources
    beanDefinitionReader.setResourceLoader(this);
    //Set the entity parser for parsing entities in XML such as DTD
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
    // Initialize the Bean definition reader and may set some parameters, such as whether to validate XML
    this.initBeanDefinitionReader(beanDefinitionReader);
    //Call the overloaded loadBeanDefinitions to load the Bean definition according to the configured resources and location.
    this.loadBeanDefinitions(beanDefinitionReader);
}

// Initialize the Bean definition reader, mainly setting whether to perform XML verification
protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {
    // Set the XML validation mode, usually depends on the application context configuration
    reader.setValidating(this.validating);
}

//Load Bean definition through XmlBeanDefinitionReader
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
    // Get an array of all configuration resources (such as XML configuration files)
    Resource[] configResources = this.getConfigResources();
    //If the configuration resources are not empty, load these resources
    if (configResources != null) {
        reader.loadBeanDefinitions(configResources);
    }

    // Get an array of all configuration file locations
    String[] configLocations = this.getConfigLocations();
    // If the configuration file location is not empty, load the configuration files specified in these locations.
    if (configLocations != null) {
        reader.loadBeanDefinitions(configLocations);
    }
}

In loadBeanDefinitions(DefaultListableBeanFactory beanFactory)the method, an instance is first created XmlBeanDefinitionReader. This reader is specially used to parse XMLthe configuration file and Beanload the definition into DefaultListableBeanFactoryit. beanDefinitionReaderRelated properties are set, including environment variables, resource loaders and entity resolvers. These settings ensure beanDefinitionReaderthat files are parsed correctly XMLand that placeholders and external resources in files are resolved.

Then, by calling initBeanDefinitionReaderthe method, you can XmlBeanDefinitionReaderperform some additional configuration on the instance, such as setting up XMLvalidation. Finally, loadBeanDefinitions(XmlBeanDefinitionReader reader)the method is called to actually perform the loading operation. This method will call the reader to actually read and parse XMLthe file, Beanloading the definition into Springthe container.

In the method, first try to get the configuration file resources loadBeanDefinitions(XmlBeanDefinitionReader reader)from the method , if such resources exist, then by loading these definitions. Second, attempts to obtain configuration file location information and, if present, loads the configuration files specified by those locations. This design allows configuration to be loaded from different sources, such as directly from a resource file or from a specified file path.getConfigResourcesXMLreaderreader

debug can see the detailed status of reader and configLocations

cke_135.png

Here we see another reader.loadBeanDefinitions(configLocations); What is this doing? Check it out below!

2.5 loadBeanDefinitions - implemented by XmlBeanDefinitionReader

When debugging, you can see that the reader here is XmlBeanDefinitionReader. Click to track the reader.loadBeanDefinitions(configLocations); method. The called method is in AbstractBeanDefinitionReader, and XmlBeanDefinitionReader inherits from AbstractBeanDefinitionReader.

cke_136.png

Here the configuration file is loaded cyclically, and there is a count += this.loadBeanDefinitions(location); Continue tracking!

cke_137.png

The logical action of this code is roughly as follows:

  1. According to the incoming resource location string, the corresponding resource is obtained through the resource loader (ResourceLoader).
  2. If the resource loader is a resource pattern resolver (ResourcePatternResolver), it will process the pattern in the path (such as wildcard characters) and load all matching resources.
  3. Read the resource, parse and register all bean definitions defined in it.
  4. If a collection of actual resources (actualResources) is provided, the parsed resources will be added to this collection.
  5. Returns the number of loaded and registered bean definitions.

Let’s focus on the key points and continue to track the loadBeanDefinitions inside.

cke_138.png

The code is brought up for analysis:

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {

// 将Resource包装为EncodedResource,允许指定编码,然后继续加载Bean定义

return this.loadBeanDefinitions(new EncodedResource(resource));

}

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {

// 断言传入的EncodedResource不为空

Assert.notNull(encodedResource, "EncodedResource must not be null");

// 如果日志级别为trace,则输出跟踪日志

if (this.logger.isTraceEnabled()) {

this.logger.trace("Loading XML bean definitions from " + encodedResource);

}

// 获取当前线程正在加载的资源集合

Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();

// 检查资源是否已经在加载中,如果是,则抛出BeanDefinitionStoreException异常,避免循环加载

if (!currentResources.add(encodedResource)) {

throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");

} else {

int var6; // 这将用来存储加载的Bean定义数量

try {

// 打开资源的InputStream进行读取

InputStream inputStream = encodedResource.getResource().getInputStream();

Throwable var4 = null;

try {

// 将InputStream封装为InputSource,XML解析器可以接受这个类型

InputSource inputSource = new InputSource(inputStream);

// 如果资源编码不为空,设置资源的编码

if (encodedResource.getEncoding() != null) {

inputSource.setEncoding(encodedResource.getEncoding());

}

// 实际加载Bean定义的方法,返回加载的Bean定义数量

var6 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());

} catch (Throwable var24) {

// 捕获Throwable以便在finally块中处理资源释放

var4 = var24;

throw var24;

} finally {

// 关闭InputStream资源

if (inputStream != null) {

if (var4 != null) {

try {

inputStream.close();

} catch (Throwable var23) {

// 添加被抑制的异常

var4.addSuppressed(var23);

}

} else {

inputStream.close();

}

}

}

} catch (IOException var26) {

// 抛出IOException异常,如果解析XML文档失败

throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var26);

} finally {

// 从当前加载的资源集合中移除该资源

currentResources.remove(encodedResource);

// 如果当前加载的资源集合为空,则从ThreadLocal中移除

if (currentResources.isEmpty()) {

this.resourcesCurrentlyBeingLoaded.remove();

}

}

// 返回加载的Bean定义数量

return var6;

}

}

In this code, loadBeanDefinitions first converts the Resource to an EncodedResource, which allows it to preserve information about the resource's encoding. It then tries to load the resource as an InputStream and convert it to an InputSource, which is required for XML parsing. Then it calls the doLoadBeanDefinitions method, which is actually responsible for parsing the XML and registering the bean definition.

In this process, the code ensures that the same resource is not loaded in a loop, and if an exception occurs while loading the resource, the resource is cleaned up appropriately and the error is reported. The number of loaded bean definitions is returned upon completion.

Let’s focus on the key steps of this code: doLoadBeanDefinitions method!

2.6 doLoadBeanDefinitions - Read and parse XML configuration file content

cke_139.png

What does the doLoadBeanDefinitions method do?

Specific steps are as follows:

  1. Use the doLoadDocument method to parse the given InputSource into a DOM Document object. This Document object represents the structure of the XML file.
  2. By calling the registerBeanDefinitions method, register the Bean definitions in the parsed Document into Spring's Bean factory. This method returns the number of registered bean definitions.
  3. If the log level is set to DEBUG, the number of loaded bean definitions is logged.

The focus here is the registerBeanDefinitions method, continue to follow the code

cke_140.png

Continue to look at the key points and finally catch up with the doRegisterBeanDefinitions method.

cke_141.png

The doRegisterBeanDefinitions(Element root) method is a method in the Spring framework used to parse bean definitions in XML configuration files and register them to the Spring container. This method is usually called after the XML file is read and converted into a DOM (Document Object Model) tree. At this time, the root element of the XML file is passed to this method through the parameter root.

The code is brought up for analysis:

protected void doRegisterBeanDefinitions(Element root) {

// 保存旧的解析代理(delegate),以便之后可以恢复

BeanDefinitionParserDelegate parent = this.delegate;

// 创建新的解析代理(delegate),用于处理当前XML根节点的解析

this.delegate = this.createDelegate(this.getReaderContext(), root, parent);

// 如果当前节点使用的是Spring默认的XML命名空间

if (this.delegate.isDefaultNamespace(root)) {

// 获取根节点的"profile"属性

String profileSpec = root.getAttribute("profile");

// 检查"profile"属性是否有文本内容

if (StringUtils.hasText(profileSpec)) {

// 按逗号、分号和空格分隔"profile"属性值,得到指定的profiles数组

String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; ");

// 如果当前环境不接受任何指定的profiles,则不加载该Bean定义文件

if (!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {

// 如果日志级别是DEBUG,则记录跳过文件的信息

if (this.logger.isDebugEnabled()) {

this.logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + this.getReaderContext().getResource());

}

// 退出方法,不进行后续处理

return;

}

}

}

// 在解析XML前进行预处理,可被重写的方法

this.preProcessXml(root);

// 解析XML根节点下的Bean定义

this.parseBeanDefinitions(root, this.delegate);

// 在解析XML后进行后处理,可被重写的方法

this.postProcessXml(root);

// 恢复旧的解析代理(delegate)

this.delegate = parent;

}

The above code snippet is an internal method used by the Spring framework to register a bean definition. This method is called when parsing the XML configuration file and registering the bean definition into the Spring container. It contains logic for processing profile attributes to decide whether to load a specific bean definition based on the runtime environment, as well as pre- and post-processing hooks that allow custom operations before and after parsing. Finally, it ensures that the resolution delegate is reset to its previous state to maintain the correct state.

Next, we have to look at how to parse xml, focusing on the parseBeanDefinitions method

2.7 parseBeanDefinitions - Parse BeanDefinition elements in XML

cke_142.png

The main purpose of the parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) method is to traverse the root node of the XML configuration file, parse and register all the beans defined in it. This method is responsible for distinguishing different types of elements, that is, standard elements under the default namespace and custom elements under the custom namespace, and processing them accordingly.

The code is brought up for analysis:

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {

// 判断根节点是否使用的是Spring的默认命名空间

if (delegate.isDefaultNamespace(root)) {

// 获取所有子节点

NodeList nl = root.getChildNodes();



// 遍历所有子节点

for (int i = 0; i < nl.getLength(); ++i) {

Node node = nl.item(i);

// 只处理Element类型的节点(过滤掉文本节点等其他类型)

if (node instanceof Element) {

Element ele = (Element)node;

// 如果子元素节点也是默认命名空间,则调用parseDefaultElement方法解析

if (delegate.isDefaultNamespace(ele)) {

this.parseDefaultElement(ele, delegate);

} else {

// 如果子元素节点不是默认命名空间,则调用parseCustomElement方法解析

// 这通常表示节点定义了自定义的行为,可能是用户自定义的标签或者是Spring扩展的标签

delegate.parseCustomElement(ele);

}

}

}

} else {

// 如果根节点不是默认命名空间,那么它可能是一个自定义标签的顶级元素

// 在这种情况下,直接调用parseCustomElement进行解析

delegate.parseCustomElement(root);

}

}

The purpose of this code is to parse the beans defined in the XML file. It examines each XML element (including root elements and child elements) and calls different processing methods based on whether these elements belong to Spring's default namespace (usually " http://www.springframework.org/schema/beans "). If the element belongs to the default namespace, then it will call parseDefaultElement to parse standard Spring configuration elements such as <bean>. If the element does not belong to the default namespace, it will be considered a custom element and parseCustomElement will be called to parse it. Custom elements are usually defined by developers or provided by Spring extensions to increase the functionality of the framework.

Here you can see that it is a loop processing Element node. The parsing action is mainly the parseDefaultElement method. Let’s continue to take a look.

cke_143.png

The parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) method is the method used by the Spring framework to parse the default namespace (that is, the Spring namespace without prefix) elements in the XML configuration file. This method specifically handles the <import>, <alias>, <bean>, and <beans> tags.

 What elements does "Spring namespace without prefix" refer to? They belong to Spring's default namespace, but do not need to specify a namespace prefix when using them. Such as <bean>, <property> or <constructor-arg>, these elements are not prefixed and they belong to the XML schema namespace defined by Spring. The default namespace is usually declared at the top of the XML file through the xmlns attribute.

The code is brought up for analysis:

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {

// 判断当前元素节点名称是否是"import"

if (delegate.nodeNameEquals(ele, "import")) {

// 如果是"import",则导入其他配置文件

this.importBeanDefinitionResource(ele);

} else if (delegate.nodeNameEquals(ele, "alias")) {

// 如果节点是"alias",则处理别名定义,为一个bean定义一个或多个别名

this.processAliasRegistration(ele);

} else if (delegate.nodeNameEquals(ele, "bean")) {

// 如果节点是"bean",则处理bean定义,这是定义Spring bean的核心元素

this.processBeanDefinition(ele, delegate);

} else if (delegate.nodeNameEquals(ele, "beans")) {

// 如果节点是"beans",意味着有嵌套的beans定义,需要递归地注册其中的bean定义

this.doRegisterBeanDefinitions(ele);

}

}

The function of this code is to determine different processing operations for different tags in the XML configuration file based on the name of the element. It handles four main tags under the Spring framework's default namespace:

  1. <import> : Import other Spring XML configuration files into the current configuration file.
  2. <alias> : Provide one or more aliases for an already defined bean.
  3. <bean> : Defines a Spring-managed bean. It is the most commonly used element and contains the detailed configuration of the bean.
  4. <beans> : Defines a collection of beans, usually the top-level element in the configuration file, but can also be a nested definition, representing a new scope or context.

In this way, Spring can build the bean factory in the application context based on these elements.

Debugging can be found that the xml has been parsed out of the preliminary prototype.

cke_144.png

It seems that the bean element is not seen here. How to parse this? Let's go step by step and see what the processBeanDefinition method is called in the parseDefaultElement method mentioned above.

2.8 processBeanDefinition - specific parsing and processing of <bean> tags

cke_145.png

The processBeanDefinition method is the method used in the Spring framework to process the <bean> XML configuration element. Its purpose is to convert the information described in the <bean> element into a BeanDefinition object used internally by Spring and register it with the Spring IoC container. This is a critical step in the Spring bean life cycle because the beans defined here will be instantiated and managed when the container starts

The code is brought up for analysis:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {

// 使用代理解析bean定义元素,这涉及将XML定义的<bean>元素转换成Spring的BeanDefinitionHolder对象,

// 该对象包含了bean定义和名称。

BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);

// 检查解析是否返回了BeanDefinitionHolder对象。

if (bdHolder != null) {

// 如有需要,对bean定义进行装饰。这可能涉及应用任何额外的属性或嵌套元素,

// 这些都是bean定义的一部分,但不是标准<bean> XML配置的一部分。

bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

try {

// 在注册中心注册bean定义。注册中心通常是持有所有bean定义的Spring IoC容器。

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());

} catch (BeanDefinitionStoreException var5) {

// 如果在bean注册过程中出现异常,报告错误上下文并抛出异常。

// 错误上下文包括bean的名称和引起问题的XML元素。

this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);

}

// 在成功注册后,通知任何监听器一个新的bean定义已被注册。

// 这是Spring事件机制的一部分,允许对容器内的特定动作作出响应。

this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));

}

// 注意:如果bdHolder为空,则意味着bean定义元素没有被正确解析

// 或者它不是要被注册的(例如,在抽象定义的情况下)。

// 因此,在这种情况下,该方法不执行任何操作。

}

This method is typically used during the Spring Framework's bean definition parsing process, and it handles the logic of creating and registering bean definitions based on the provided XML elements. BeanDefinitionParserDelegate is a helper class that handles the details of parsing specific Spring XML structures.

When debugging this class, I found that the class and id of this bean have been parsed.

cke_146.png

Some people may be curious, how to encapsulate xml elements into BeanDefinitionHolder?

cke_147.png

The parseBeanDefinitionElement method is used to parse the definition of the <bean> element in the Spring configuration file and generate the corresponding BeanDefinitionHolder object. BeanDefinitionHolder is a wrapper class that encapsulates a BeanDefinition instance and the name of the definition (i.e., the id of the bean) and the alias (if any).

The code is brought up for analysis:

@Nullable

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {

// 调用重载方法parseBeanDefinitionElement,并将BeanDefinition设置为null

return this.parseBeanDefinitionElement(ele, (BeanDefinition)null);

}

@Nullable

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {

// 获取元素的id属性

String id = ele.getAttribute("id");

// 获取元素的name属性

String nameAttr = ele.getAttribute("name");

// 创建别名列表

List<String> aliases = new ArrayList();

if (StringUtils.hasLength(nameAttr)) {

// 如果name属性非空,则使用分隔符分割name字符串,并将结果添加到别名列表

String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; ");

aliases.addAll(Arrays.asList(nameArr));

}

// 默认情况下bean的名称使用id属性的值

String beanName = id;

if (!StringUtils.hasText(id) && !aliases.isEmpty()) {

// 如果id为空且别名列表非空,则使用别名列表中的第一个作为bean名称,并从列表中移除它

beanName = aliases.remove(0);

if (this.logger.isTraceEnabled()) {

this.logger.trace("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases");

}

}

if (containingBean == null) {

// 如果不是嵌套bean定义,则检查bean名称和别名的唯一性

this.checkNameUniqueness(beanName, aliases, ele);

}

// 解析bean定义元素,返回AbstractBeanDefinition对象

AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);

if (beanDefinition != null) {

if (!StringUtils.hasText(beanName)) {

// 如果bean名称为空,则尝试生成bean名称

try {

if (containingBean != null) {

// 如果是内部bean,则使用特定的生成策略

beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);

} else {

// 否则使用默认策略

beanName = this.readerContext.generateBeanName(beanDefinition);

String beanClassName = beanDefinition.getBeanClassName();

if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {

// 如果bean类名不为空,且生成的bean名称以类名开头,且未被使用,则将类名添加到别名列表

aliases.add(beanClassName);

}

}

if (this.logger.isTraceEnabled()) {

this.logger.trace("Neither XML 'id' nor 'name' specified - using generated bean name [" + beanName + "]");

}

} catch (Exception var9) {

// 在名称生成过程中捕获异常,并记录错误

this.error(var9.getMessage(), ele);

return null;

}

}

// 将别名列表转换为数组

String[] aliasesArray = StringUtils.toStringArray(aliases);

// 创建并返回BeanDefinitionHolder对象

return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);

} else {

// 如果bean定义为空,则返回null

return null;

}

}

This code is responsible for parsing the <bean> element in the XML, extracting the id and name attributes, and handling possible aliases. It then creates an AbstractBeanDefinition, which is an abstract representation of the bean definition in Spring. If no bean name is specified, it attempts to generate a unique name and adds an alias if necessary. Ultimately, it returns a BeanDefinitionHolder that contains all this information. If any problems are encountered during parsing, an error is logged and null is returned.

In this code, another overloaded method will be called, this.parseBeanDefinitionElement(ele, beanName, containingBean); this code contains the parseBeanDefinitionAttributes method that encapsulates other attributes of <bean>. Let’s take a look.

cke_148.png

cke_149.png

The method parseBeanDefinitionAttributes is used to parse the attributes of the <bean> element in the Spring configuration file and apply these attributes to the incoming AbstractBeanDefinition object. This process is to set the scope of the bean, whether to delay initialization, autowiring mode, dependencies, whether to be a candidate for autowiring, whether it is the priority bean (primary), initialization method, destruction method, factory method and factory bean name. and other properties. Methods handle default values ​​for properties and handle legacy formats for some properties (such as singleton).

Propose code analysis directly:

public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {

// 检查是否使用了已废弃的singleton属性,如果存在,则报错提示应该升级到scope属性

if (ele.hasAttribute("singleton")) {

this.error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);

// 如果存在scope属性,则设置bean的作用域

} else if (ele.hasAttribute("scope")) {

bd.setScope(ele.getAttribute("scope"));

// 如果没有设置scope属性但是有包含bean,则设置为包含bean的作用域

} else if (containingBean != null) {

bd.setScope(containingBean.getScope());

}

// 如果设置了abstract属性,根据该属性的值设置bean定义是否为抽象

if (ele.hasAttribute("abstract")) {

bd.setAbstract("true".equals(ele.getAttribute("abstract")));

}

// 解析lazy-init属性,默认使用配置的默认值,如果设置了则覆盖

String lazyInit = ele.getAttribute("lazy-init");

if (this.isDefaultValue(lazyInit)) {

lazyInit = this.defaults.getLazyInit();

}

bd.setLazyInit("true".equals(lazyInit));

// 解析autowire属性,将字符串值转换为相应的自动装配模式

String autowire = ele.getAttribute("autowire");

bd.setAutowireMode(this.getAutowireMode(autowire));

// 解析depends-on属性,将字符串值转换为数组,并设置为bean定义的依赖

if (ele.hasAttribute("depends-on")) {

String dependsOn = ele.getAttribute("depends-on");

bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, ",; "));

}

// 解析autowire-candidate属性,设置bean是否可作为自动装配的候选者

String autowireCandidate = ele.getAttribute("autowire-candidate");

if (this.isDefaultValue(autowireCandidate)) {

String defaultValue = this.defaults.getAutowireCandidates();

if (defaultValue != null) {

String[] patterns = StringUtils.commaDelimitedListToStringArray(defaultValue);

bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));

}

} else {

bd.setAutowireCandidate("true".equals(autowireCandidate));

}

// 解析primary属性,设置bean是否为primary

if (ele.hasAttribute("primary")) {

bd.setPrimary("true".equals(ele.getAttribute("primary")));

}

// 解析init-method属性,设置bean的初始化方法

String initMethodName = ele.getAttribute("init-method");

if (ele.hasAttribute("init-method")) {

bd.setInitMethodName(initMethodName);

// 如果没有设置但是有默认值,则使用默认值

} else if (this.defaults.getInitMethod() != null) {

bd.setInitMethodName(this.defaults.getInitMethod());

bd.setEnforceInitMethod(false);

}

// 解析destroy-method属性,设置bean的销毁方法

String destroyMethodName = ele.getAttribute("destroy-method");

if (ele.hasAttribute("destroy-method")) {

bd.setDestroyMethodName(destroyMethodName);

// 如果没有设置但是有默认值,则使用默认值

} else if (this.defaults.getDestroyMethod() != null) {

bd.setDestroyMethodName(this.defaults.getDestroyMethod());

bd.setEnforceDestroyMethod(false);

}

// 解析factory-method属性,设置bean的工厂方法

if (ele.hasAttribute("factory-method")) {

bd.setFactoryMethodName(ele.getAttribute("factory-method"));

}

// 解析factory-bean属性,设置bean的工厂bean名

if (ele.hasAttribute("factory-bean")) {

bd.setFactoryBeanName(ele.getAttribute("factory-bean"));

}

// 返回配置好的bean定义

return bd;

}

The core function of this code is to convert the properties in the XML configuration file into properties of the BeanDefinition object. For each property, it first checks whether the property exists, and if it exists, reads its value and sets it into the BeanDefinition object. If a default value exists and no specific value is provided in the XML, the default value is used. In this way, the Spring container is able to create and manage beans based on configuration files.

2.9 Summary

The complete process from reading the XML configuration file to registering the BeanDefinition:

cke_150.png

1. Load the configuration file :

  • The "Create context" step in the figure corresponds to instantiating ClassPathXmlApplicationContext, and the XML file path will be passed in at this time.
  • ClassPathXmlApplicationContext accepts one or more XML file paths as construction parameters.

2. Initialize BeanFactory and refresh :

  • In the figure, the "execute refresh" step indicates that the refresh() method is called. This method starts the initialization and refresh process of the container.
  • Initialize the BeanFactory in the refresh() method and prepare to parse the configuration file.

3. Read the XML configuration file :

  • The "Load Bean Definition" step in the figure represents the role of XmlBeanDefinitionReader, which is responsible for reading and loading XML configuration files.
  • XmlBeanDefinitionReader is responsible for reading the incoming XML configuration file.

4. Parse the XML file :

  • The "Parse XML" step in the figure represents the DefaultBeanDefinitionDocumentReader processing the XML file, which includes parsing the top-level <beans> tag.
  • DefaultBeanDefinitionDocumentReader starts processing XML files and parses top-level tags such as <beans>.
  • For the parsing of <bean> elements, first check whether the element is in the default namespace. If so, parse the default element; if not, elements outside the default namespace are considered custom elements and are handled by delegate.parseCustomElement(ele).

5.Parsing and registration of Bean definition :

  • The "Register Bean Definition", "Process Alias", "Process Bean" and "Process Import" steps in the figure correspond to various parsing activities of BeanDefinitionParserDelegate, which involves parsing the bean's id, name, alias, attributes, sub-elements, etc. And register the parsing results to BeanDefinitionRegistry.
  • Use BeanDefinitionParserDelegate to parse the details of the <bean> element, including the bean's id, name, alias, etc.
  • Parse the attributes of the <bean> element, such as scope, lazy-init, etc., and set these values ​​​​to the BeanDefinition instance.
  • If the <bean> element contains sub-elements (such as <property> or <constructor-arg>), they will also be parsed and added to the BeanDefinition in the form of corresponding metadata.
  • The generated BeanDefinition will be registered in BeanDefinitionRegistry, using the BeanDefinitionReaderUtils.registerBeanDefinition method.
  • If any errors occur during the parsing process, error information will be recorded through the error method.

6. Event release :

  • After registering the BeanDefinition, the ApplicationContext will publish a component registration event to notify the relevant listeners. This process allows components that implement the ApplicationListener interface or annotate with @EventListener to receive this event and respond as needed. For example, you can use this event to trigger some custom logic, such as additional configuration checks, starting some post-processing operations, etc.

This detailed process shows the complex process involved from loading the configuration file to parsing and registering the BeanDefinition. It shows the internal mechanism of the Spring framework to handle bean declarations and dependencies. This is the basis of Spring's core functionality of dependency injection, ensuring that beans can be instantiated and managed as defined.

3. Source code reading exercises

1. XML configuration file parsing:

  • What components are used by the Spring container when parsing Spring configuration files?

  The Spring container mainly uses the XmlBeanDefinitionReader class when parsing configuration files. In addition, BeanDefinitionDocumentReader is also used for specific document reading.

  • What role does BeanDefinitionReader play in configuration file parsing?

  BeanDefinitionReader is responsible for reading bean definitions from XML files and converting them into Spring's internal BeanDefinition objects.

  • When is the parseBeanDefinitionElement method called? What is its output?

  parseBeanDefinitionElement is called when the XML element is read, and its output is a BeanDefinitionHolder object, which contains the bean definition as well as the name and alias.

2. Bean definition analysis:

  • Describes the process of a bean definition starting from reading XML elements to generating a BeanDefinition object.

  BeanDefinition objects are created by reading the <bean> element in XML and extracting the relevant properties. These properties include the bean's class name, scope, life cycle callbacks, etc.

  • What is the role of the parseBeanDefinitionAttributes method in the entire parsing process?

  The parseBeanDefinitionAttributes method is used to extract the attributes on the bean element and set them into the AbstractBeanDefinition object.

  • Which XML attributes are processed by the parseBeanDefinitionAttributes method, and how do they affect the generated BeanDefinition object?

  The attributes processed by the parseBeanDefinitionAttributes method include scope, lazy-init, autowire, etc. These attributes determine the behavior of the bean and how it interacts with other beans.

3. Bean names and aliases:

  • How does Spring handle this if the bean's id or name is not provided in the XML element?

  If no id or name is provided, Spring will automatically generate a unique bean name. It may be based on the class name plus a certain serial number. Tip: It was mentioned when analyzing the parseBeanDefinitionElement method.

  • What is the use of aliases in Spring? How are aliases handled in the parseBeanDefinitionElement method?

  Alias ​​can provide an additional name for a bean, which is useful when you need to refer to the same bean but use different names in different contexts. In the parseBeanDefinitionElement method, aliases are handled by parsing the name attribute and using commas, semicolons, or spaces as delimiters.

4. Bean scope and life cycle attributes:

  • How to define the scope of a bean? What is the difference between singleton and prototype?

  Define the scope of a bean by setting the scope attribute of the <bean> element. Singleton represents a globally unique instance, while prototype represents a new instance created for each request.

  • What impact do these properties lazy-init, init-method and destroy-method have on the bean life cycle?

  The lazy-init attribute determines whether the bean should be lazily initialized at startup, and the init-method and destroy-method define the methods that are called when the bean is initialized and destroyed.

5. Bean registration:

  • Once the BeanDefinition object is created, how does Spring register it with the container?

  After the BeanDefinition object is parsed, it is registered in the Spring container through the DefaultListableBeanFactory.registerBeanDefinition method.

  • During the registration process, if a bean name conflict is found, how will Spring handle it?

  If a name conflict is found, a BeanDefinitionStoreException is thrown. If beans with the same name are defined in different configuration files, the latter will usually override the former.

6. Exception handling:

  • How does Spring give feedback to the user when the XML configuration is incorrect or illegal attributes are used?

  Spring will notify users of configuration errors by throwing BeanDefinitionStoreException. The exception message details the cause and location of the error.

  • Analyze the error handling mechanism in Spring. How does it help developers debug configurations?

  Spring's error handling mechanism includes detailed exception information and precise location, which is very helpful for developers to quickly identify configuration errors.

4. Frequently Asked Questions

4.1 During the refresh process, what is the life cycle of Bean? How is the state of each Bean managed?

1. Instantiate BeanFactory :

  • At the beginning of the refresh method, Spring will instantiate a new BeanFactory, usually DefaultListableBeanFactory, as a container for creating Bean instances.

2. Load the Bean definition :

  • Then, refresh calls loadBeanDefinitions to load and register the Bean definition. These definitions can come from XML configuration files, Java configuration classes, or scanned annotations.

3.Execution of BeanFactoryPostProcessor :

  • After all bean definitions have been loaded, but before the beans are instantiated, Spring calls the BeanFactoryPostProcessor. These handlers can modify bean definitions (configuration metadata).

4.Registration of BeanPostProcessor :

  • Next, Spring registers the BeanPostProcessor instance. These handlers can modify Bean instances (objects after creation and initialization).

5. Pre-instantiation of singleton Bean :

  • Spring will then pre-instantiate the singleton bean. For singleton-scoped beans, Spring creates and configures these beans and then places them in the cache.

6. Dependency injection :

  • After the bean is instantiated, Spring performs dependency injection. At this point, the Bean's properties will be set and related dependencies will be injected.

7.Bean initialization :

  • Afterwards, the Bean will be initialized. If the Bean implements the InitializingBean interface, the afterPropertiesSet method will be called; or if the init-method is defined, the specified method will also be called.

8.Call of Aware interface :

  • If the bean implements any Aware interface, such as ApplicationContextAware or BeanNameAware, they will be called before initialization.

9.BeanPostProcessor post-processing :

  • BeanPostProcessor's pre-processing (postProcessBeforeInitialization) and post-processing (postProcessAfterInitialization) methods are called before and after Bean initialization, and they can further customize the Bean.

10.Event release :

  • Once all singleton beans have been initialized, Spring publishes a ContextRefreshedEvent indicating that the ApplicationContext has been refreshed.

11.Use Beans :

  • At this point, all beans are ready and can be used in other parts of the application.

12. Close the container :

  • When the application context is closed, if the Bean implements the DisposableBean interface, the destroy method will be called; or if the destroy-method method is defined, it will also be executed to clean up resources.

During the entire life cycle, the state of each Bean is tracked and managed by ApplicationContext and BeanFactory, from creation, dependency injection, initialization, to destruction, ensuring that Beans are created and cleaned up at the correct time.

4.2 Is the refresh method automatically triggered? If not, under what conditions does it need to be triggered manually?

The refresh method in Spring:

1. When to trigger:

  • Automatic triggering : When initializing the ApplicationContext, such as using new ClassPathXmlApplicationContext("config.xml") in the application, the refresh method will be automatically called during the startup process of the Spring container.
  • Manual triggering : If the configuration needs to be reloaded while the application is running (the configuration file may be modified), you can manually call the refresh method to achieve this. But this is usually used in special scenarios during the development or testing phase, as it causes the entire application context to be rebuilt, including all Bean objects.

2. Why manual triggering is needed:

  • Normally, the Spring container only needs to load the configuration once and initialize each bean once when starting. Unless there are special needs, such as dynamically adjusting the log level, reloading specific beans in the configuration file, manual triggering is not required.

The refresh method in Spring Boot:

Spring Boot greatly simplifies the configuration and startup process of Spring applications. It automatically configures Spring's ApplicationContext and calls the refresh method when appropriate.

1. Automatic trigger:

  • When you use Spring Boot's SpringApplication.run() method to start an application, Spring Boot automatically creates an ApplicationContext and calls the refresh method internally. This process is automatic and developers usually don't need to be concerned.

2. Possible manual trigger scenarios:

  • Spring Boot provides the actuator module, where the /refresh endpoint can be used to reload configuration (usually used in conjunction with Spring Cloud Config). This is not a call to the refresh method of ApplicationContext in the traditional sense, but a mechanism that triggers the reloading of part of the configuration, especially beans marked with @RefreshScope, which can be updated without restarting the entire application.

General advice:

  • For developers, the refresh method should not be called manually at will in a production environment. Because this will cause the entire application to reload, affecting performance and possibly causing service interruption.
  • If you need to dynamically update the configuration, you should use the /refresh endpoint of Spring Cloud Config and Spring Boot Actuator, which is a more secure and controlled way to update the configuration.

4.3 Does the refresh method behave differently in Spring Boot? Does Spring Boot provide a better way to handle changes in application context?

In Spring Boot, the basic behavior of the refresh method remains the same because Spring Boot is built on top of Spring and follows the same basic principles. However, Spring Boot does provide more automation and convenience for application context management and refresh:

1. Automatic configuration:

  • Spring Boot's unique automatic configuration feature reduces the need for manual refresh scenarios. On startup, it automatically wires the bean, and there is usually no need to explicitly call refresh.

2.Externalization placement :

  • Spring Boot supports a powerful external configuration mechanism, allowing configuration to be injected through configuration files, environment variables, etc. This makes it possible to change the configuration without refreshing the context.

3. Conditional refresh :

  • Spring Boot uses conditional annotations (such as @ConditionalOnClass, @ConditionalOnBean, etc.), which allows the context to dynamically adjust its configuration according to the environment or specific conditions, reducing the need to manually trigger refresh.

4. Life cycle management :

  • Through the SpringApplication class, Spring Boot provides additional management capabilities for the application life cycle. It handles many tasks that need to be done manually in traditional Spring applications, such as initializing and refreshing the application context.

5.Actuator endpoints:

  • For running applications, Spring Boot Actuator provides a series of management and monitoring endpoints, some of which can be used to refresh the configuration (such as /refresh endpoint) or restart the context (such as /restart endpoint), which can be used instead in some cases Full application restart.

6. Configure change monitoring :

  • Applications using Spring Cloud Config can automatically refresh the context when configuration changes. Changes on the config server can be listened for and can trigger an automatic refresh of the client context without manual intervention.

7. Error handling :

  • Spring Boot has a default error handling mechanism, especially in web applications, which provides a default error page and /error endpoint. Additionally, developers can customize error handling to fit specific needs.

To sum up, Spring Boot provides a more automated way to handle changes in application context. In many cases, there is no need to manually call the refresh method. However, if you need to dynamically change the Bean configuration at runtime and want these changes to take effect immediately, you may also need to use the refresh method provided by Spring or use the relevant endpoints of Spring Boot Actuator to achieve this purpose.

Click to follow and learn about Huawei Cloud’s new technologies as soon as possible~

Alibaba Cloud suffered a serious failure and all products were affected (restored). Tumblr cooled down the Russian operating system Aurora OS 5.0. New UI unveiled Delphi 12 & C++ Builder 12, RAD Studio 12. Many Internet companies urgently recruit Hongmeng programmers. UNIX time is about to enter the 1.7 billion era (already entered). Meituan recruits troops and plans to develop the Hongmeng system App. Amazon develops a Linux-based operating system to get rid of Android's dependence on .NET 8 on Linux. The independent size is reduced by 50%. FFmpeg 6.1 "Heaviside" is released
{{o.name}}
{{m.name}}

Guess you like

Origin my.oschina.net/u/4526289/blog/10143075