Spring source code parsing 8: default namespace processor in XML configuration

Time:2022-5-3

Spring source code parsing 8: default namespace processor in XML configuration

staySpring source code analysis 5: bean configuration, definition and registrationIn, the default namespace processor in some XML configurations has not been resolved

Here only a few commonly used are analyzed

  • SimpleConstructorNamespaceHandler
  • SimplePropertyNamespaceHandler
  • ContextNamespaceHandler
  • TaskNamespaceHandler
  • CacheNamespaceHandler
  • MvcNamespaceHandler

Others who are interested can explore by themselves

1. SimpleConstructorNamespaceHandler

SimpleConstructorNamespaceHandler
The main function of is to instantiate the beans configured as follows

<bean id="author" class="..TestBean" c:name="Enescu" c:work-ref="compositions"/>

takename="Enescu", work=bean[compositions]Instantiate beans as arguments to constructors

public class SimpleConstructorNamespaceHandler implements NamespaceHandler {
    @Override
    public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
        if (node instanceof Attr) {
            Attr attr = (Attr) node;
            //Remove blank on both sides
            String argName = StringUtils.trimWhitespace(parserContext.getDelegate().getLocalName(attr));
            //Remove blank on both sides
            String argValue = StringUtils.trimWhitespace(attr.getValue());

            //Constructor parameter set
            ConstructorArgumentValues cvs = definition.getBeanDefinition().getConstructorArgumentValues();
            boolean ref = false;

            //If the field name results with "- ref", it indicates the reference to other beans at run time
            if (argName.endsWith(REF_SUFFIX)) {
                ref = true;
                argName = argName.substring(0, argName.length() - REF_SUFFIX.length());
            }

            //Encapsulate values with valueholder
            ValueHolder valueHolder = new ValueHolder(ref ? new RuntimeBeanReference(argValue) : argValue);
            valueHolder.setSource(parserContext.getReaderContext().extractSource(attr));

            //With "" If the parameter is passed in the order of the first name, it means there is no parameter
            if (argName.startsWith(DELIMITER_PREFIX)) {
                String arg = argName.substring(1).trim();

                //If no order is specified, add directly
                if (!StringUtils.hasText(arg)) {
                    cvs.addGenericArgumentValue(valueHolder);
                }
                //If there is a specified order, add in the specified order
                else {
                    int index = -1;
                    try {
                        index = Integer.parseInt(arg);
                    }
                    catch (NumberFormatException ex) {
                        // ...  Code omission
                    }

                    // ...  Code omission

                    //Add to CVS
                    cvs.addIndexedArgumentValue(index, valueHolder);
                }
            }
            //Parameter with name
            else {
                // ...  Code omission

                //Add to CVS
                valueHolder.setName(Conventions.attributeNameToPropertyName(argName));
                cvs.addGenericArgumentValue(valueHolder);
            }
        }
        return definition;
    }
}

2. SimplePropertyNamespaceHandler

SimplePropertyNamespaceHandler
The main function of is to instantiate the beans configured as follows

<bean id="rob" class="..TestBean" p:name="Rob Harrop" p:spouse-ref="sally"/>

takename="Rob Harrop", spouse=bean[sally]Inject into beans as attributes

public class SimplePropertyNamespaceHandler implements NamespaceHandler {
    @Override
    public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
        if (node instanceof Attr) {
            Attr attr = (Attr) node;
            //Attribute name
            String propertyName = parserContext.getDelegate().getLocalName(attr);
            //Attribute value
            String propertyValue = attr.getValue();
            //Attribute Collection
            MutablePropertyValues pvs = definition.getBeanDefinition().getPropertyValues();

            //If the field name results with "- ref", it indicates the reference to other beans at run time
            if (propertyName.endsWith(REF_SUFFIX)) {
                propertyName = propertyName.substring(0, propertyName.length() - REF_SUFFIX.length());
                //Change the field name from dash - or underscore_ Transformed into a hump
                pvs.add(Conventions.attributeNameToPropertyName(propertyName), new RuntimeBeanReference(propertyValue));
            }
            else {
                //Change the field name from dash - or underscore_ Transformed into a hump
                pvs.add(Conventions.attributeNameToPropertyName(propertyName), propertyValue);
            }
        }
        return definition;
    }
}

3. ContextNamespaceHandler

public class ContextNamespaceHandler extends NamespaceHandlerSupport {
    @Override
    public void init() {
        registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
        registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
        registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
        registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
        registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
        registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
        registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
        registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
    }
}

3.1. context:property-placeholder

PropertyPlaceholderBeanDefinitionParser
The main function of is parsing<context:property-placeholder/>Element, which is used when defining a bean${}Properties that reference external sources

Look at the inheritance relationship first

- AbstractBeanDefinitionParser
  - AbstractSingleBeanDefinitionParser
    - AbstractPropertyLoadingBeanDefinitionParser
      - PropertyPlaceholderBeanDefinitionParser

3.1.1. AbstractBeanDefinitionParser

AbstractBeanDefinitionParser
The main function of is to realizeBeanDefinitionParser
InterfacedparseMethod, which provides the basic function of parsing from configuration to object

public abstract class AbstractBeanDefinitionParser implements BeanDefinitionParser {
    @Override
    public final BeanDefinition parse(Element element, ParserContext parserContext) {
        //Parse element
        AbstractBeanDefinition definition = parseInternal(element, parserContext);

        try {
            //Get the ID of the bean
            String id = resolveId(element, definition, parserContext);

            String[] aliases = null;
            //Gets the name attribute, separated by commas into multiple aliases
            if (shouldParseNameAsAliases()) {
                String name = element.getAttribute(NAME_ATTRIBUTE);
                if (StringUtils.hasLength(name)) {
                    aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
                }
            }

            //Encapsulated as beandefinitionholder
            BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
            //Register in registry
            registerBeanDefinition(holder, parserContext.getRegistry());

            // ...  Code omission
        }
        catch (BeanDefinitionStoreException ex) {
            // ...  Code omission
        }
        return definition;
    }

    //Parse element,由子类实现
    protected abstract AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext);

    //Get the ID of the bean,先获取id属性,其次name属性,都没有,生成默认的名字
    protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
            throws BeanDefinitionStoreException {
        // ...  Code omission
    }
}

3.1.2. AbstractSingleBeanDefinitionParser

AbstractSingleBeanDefinitionParser
The main function of is to support beans that are parsed into singletons

public abstract class AbstractSingleBeanDefinitionParser extends AbstractBeanDefinitionParser {
    @Override
    protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
        //Create a constructor
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
        //Parent element
        String parentName = getParentName(element);
        if (parentName != null) {
            builder.getRawBeanDefinition().setParentName(parentName);
        }
        // beanClass
        Class<?> beanClass = getBeanClass(element);
        if (beanClass != null) {
            builder.getRawBeanDefinition().setBeanClass(beanClass);
        }
        // beanClassName
        else {
            String beanClassName = getBeanClassName(element);
            if (beanClassName != null) {
                builder.getRawBeanDefinition().setBeanClassName(beanClassName);
            }
        }

        // ...  Code omission

        //Resolve to constructor
        doParse(element, parserContext, builder);
        return builder.getBeanDefinition();
    }

    //Resolve to constructor,由子类实现
    protected void doParse(Element element, BeanDefinitionBuilder builder) {}
}

3.1.3. AbstractPropertyLoadingBeanDefinitionParser

AbstractPropertyLoadingBeanDefinitionParser
The main function of is parsingcontext:property-...element

abstract class AbstractPropertyLoadingBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
    @Override
    protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
        //Location attribute
        String location = element.getAttribute("location");
        if (StringUtils.hasLength(location)) {
            location = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(location);
            String[] locations = StringUtils.commaDelimitedListToStringArray(location);
            builder.addPropertyValue("locations", locations);
        }

        //Properties ref property
        String propertiesRef = element.getAttribute("properties-ref");
        if (StringUtils.hasLength(propertiesRef)) {
            builder.addPropertyReference("properties", propertiesRef);
        }

        //File encoding attribute
        String fileEncoding = element.getAttribute("file-encoding");
        if (StringUtils.hasLength(fileEncoding)) {
            builder.addPropertyValue("fileEncoding", fileEncoding);
        }

        //Order attribute
        String order = element.getAttribute("order");
        if (StringUtils.hasLength(order)) {
            builder.addPropertyValue("order", Integer.valueOf(order));
        }

        //Ignore resource not found attribute
        builder.addPropertyValue("ignoreResourceNotFound",
                Boolean.valueOf(element.getAttribute("ignore-resource-not-found")));

        //Local override property
        builder.addPropertyValue("localOverride",
                Boolean.valueOf(element.getAttribute("local-override")));
    }
}

3.1.4. PropertyPlaceholderBeanDefinitionParser

PropertyPlaceholderBeanDefinitionParser
The main function of is parsingcontext:property-placeholderelement

class PropertyPlaceholderBeanDefinitionParser extends AbstractPropertyLoadingBeanDefinitionParser {
    @Override
    protected Class<?> getBeanClass(Element element) {
        //Use this class to implement beans
        return org.springframework.beans.factory.config.PropertyPlaceholderConfigurer.class;
    }

    @Override
    protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
        super.doParse(element, parserContext, builder);

        //Ignore unresolved property
        builder.addPropertyValue("ignoreUnresolvablePlaceholders",
                Boolean.valueOf(element.getAttribute("ignore-unresolvable")));

        //System properties mode property
        String systemPropertiesModeName = element.getAttribute(SYSTEM_PROPERTIES_MODE_ATTRIBUTE);
        if (StringUtils.hasLength(systemPropertiesModeName) &&
                !systemPropertiesModeName.equals(SYSTEM_PROPERTIES_MODE_DEFAULT)) {
            builder.addPropertyValue("systemPropertiesModeName", "SYSTEM_PROPERTIES_MODE_" + systemPropertiesModeName);
        }

        //Value separator attribute
        if (element.hasAttribute("value-separator")) {
            builder.addPropertyValue("valueSeparator", element.getAttribute("value-separator"));
        }
        //Trim values attribute
        if (element.hasAttribute("trim-values")) {
            builder.addPropertyValue("trimValues", element.getAttribute("trim-values"));
        }
        //Null value attribute
        if (element.hasAttribute("null-value")) {
            builder.addPropertyValue("nullValue", element.getAttribute("null-value"));
        }
    }
}

3.2. context:property-override

PropertyOverrideBeanDefinitionParser
The main function of is parsing<context:property-override/>Element to specify the final result for the attributes of the bean in the XML configuration file

class PropertyOverrideBeanDefinitionParser extends AbstractPropertyLoadingBeanDefinitionParser {
    @Override
    protected Class<?> getBeanClass(Element element) {
        //Use this class to implement beans
        return PropertyOverrideConfigurer.class;
    }

    @Override
    protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
        super.doParse(element, parserContext, builder);

        //Ignore unresolved property
        builder.addPropertyValue("ignoreInvalidKeys",
                Boolean.valueOf(element.getAttribute("ignore-unresolvable")));

    }
}

3.3. context:annotation-config

AnnotationConfigBeanDefinitionParser
The main function of is parsing<context:annotation-config/>Element, using@AutowiredAuto assemble bean

public class AnnotationConfigBeanDefinitionParser implements BeanDefinitionParser {
    @Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        Object source = parserContext.extractSource(element);

        //Get all relevant bean definitions of registry
        Set<BeanDefinitionHolder> processorDefinitions =
                AnnotationConfigUtils.registerAnnotationConfigProcessors(parserContext.getRegistry(), source);

        // ...  Code omission

        //Register bean definitions
        for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
            parserContext.registerComponent(new BeanComponentDefinition(processorDefinition));
        }

        // ...  Code omission

        return null;
    }
}

3.4. context:component-scan

ComponentScanBeanDefinitionParser
The main function of is parsing<context:component-scan/>Element to automatically scan the annotation beans under the specified package

public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {
    @Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        //Base package attribute
        String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
        basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
        //Separating multiple packages
        String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
                ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

        //Create and configure scanned objects
        ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
        //Scan components in package
        Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
        //Register components into context
        registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

        return null;
    }
}

aboutcontext:That’s all for the analysis of command space. Others who are interested can explore it by themselves

4. TaskNamespaceHandler

public class TaskNamespaceHandler extends NamespaceHandlerSupport {
    @Override
    public void init() {
        this.registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
        this.registerBeanDefinitionParser("executor", new ExecutorBeanDefinitionParser());
        this.registerBeanDefinitionParser("scheduled-tasks", new ScheduledTasksBeanDefinitionParser());
        this.registerBeanDefinitionParser("scheduler", new SchedulerBeanDefinitionParser());
    }
}

4.1. task:annotation-driven

AnnotationDrivenBeanDefinitionParser
The main function of is parsing<task:annotation-driven/>Element, turn on the timer switch, and automatically scan the annotated timer in the program

public class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
    @Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        Object source = parserContext.extractSource(element);

        // ...  Code omission

        //Get registry
        BeanDefinitionRegistry registry = parserContext.getRegistry();

        //Mode attribute
        String mode = element.getAttribute("mode");
        //Use AspectJ to perform asynchronous tasks
        if ("aspectj".equals(mode)) {
            // mode="aspectj"
            registerAsyncExecutionAspect(element, parserContext);
        }
        //Use built-in functions to perform asynchronous tasks
        else {
            //The bean "org. Springframework. Context. Annotation. Internalasyncannotationprocessor" already exists
            if (registry.containsBeanDefinition(TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)) {
                // ...  Code omission
            }
            else {
                //Use the class "org. Springframework. Scheduling. Annotation. Asyncannotationbeanpostprocessor"
                //To configure the bean "org. Springframework. Context. Annotation. Internalasyncannotationprocessor"
                BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
                        "org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor");
                builder.getRawBeanDefinition().setSource(source);
                //Executor property
                String executor = element.getAttribute("executor");
                if (StringUtils.hasText(executor)) {
                    builder.addPropertyReference("executor", executor);
                }
                //Exception handler property
                String exceptionHandler = element.getAttribute("exception-handler");
                if (StringUtils.hasText(exceptionHandler)) {
                    builder.addPropertyReference("exceptionHandler", exceptionHandler);
                }
                //Proxy target class attribute
                if (Boolean.parseBoolean(element.getAttribute(AopNamespaceUtils.PROXY_TARGET_CLASS_ATTRIBUTE))) {
                    builder.addPropertyValue("proxyTargetClass", true);
                }
                //Register components to registry and context
                registerPostProcessor(parserContext, builder, TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME);
            }
        }

        //The bean "org. Springframework. Context. Annotation. Internalscheduledannotationprocessor" already exists
        if (registry.containsBeanDefinition(TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            // ...  Code omission
        }
        else {
            //Use the class "org. Springframework. Scheduling. Annotation. Scheduledannotationbeanpostprocessor"
            //To configure the bean "org. Springframework. Context. Annotation. Internalscheduledannotationprocessor"
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
                    "org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor");
            builder.getRawBeanDefinition().setSource(source);
            //Scheduler properties
            String scheduler = element.getAttribute("scheduler");
            if (StringUtils.hasText(scheduler)) {
                builder.addPropertyReference("scheduler", scheduler);
            }
            //Register components to registry and context
            registerPostProcessor(parserContext, builder, TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME);
        }

        // ...  Code omission

        return null;
    }

    //Use AspectJ to perform asynchronous tasks
    private void registerAsyncExecutionAspect(Element element, ParserContext parserContext) {
        //The bean "org. Springframework. Scheduling. Config. Internalasyncexecutionaspect" does not exist
        if (!parserContext.getRegistry().containsBeanDefinition(TaskManagementConfigUtils.ASYNC_EXECUTION_ASPECT_BEAN_NAME)) {
            //Use the class "org. Springframework. Scheduling. AspectJ. Annotationasyncexecutionaspect"
            //To configure the bean "org. Springframework. Scheduling. Config. Internalasyncexecutionaspect"
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ASYNC_EXECUTION_ASPECT_CLASS_NAME);
            //Use factorymethod to initialize the bean
            builder.setFactoryMethod("aspectOf");
            //Executor property
            String executor = element.getAttribute("executor");
            if (StringUtils.hasText(executor)) {
                builder.addPropertyReference("executor", executor);
            }
            //Exception handler property
            String exceptionHandler = element.getAttribute("exception-handler");
            if (StringUtils.hasText(exceptionHandler)) {
                builder.addPropertyReference("exceptionHandler", exceptionHandler);
            }
            //Register bean
            parserContext.registerBeanComponent(new BeanComponentDefinition(builder.getBeanDefinition(),
                    TaskManagementConfigUtils.ASYNC_EXECUTION_ASPECT_BEAN_NAME));
        }
    }
}

4.2. task:executor

ExecutorBeanDefinitionParser
The main function of is parsing<task:executor/>Element to configure the task executor

public class ExecutorBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
    @Override
    protected String getBeanClassName(Element element) {
        //Use this class to implement beans
        return "org.springframework.scheduling.config.TaskExecutorFactoryBean";
    }

    @Override
    protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
        //Keep alive attribute
        String keepAliveSeconds = element.getAttribute("keep-alive");
        if (StringUtils.hasText(keepAliveSeconds)) {
            builder.addPropertyValue("keepAliveSeconds", keepAliveSeconds);
        }
        //Queue capacity attribute
        String queueCapacity = element.getAttribute("queue-capacity");
        if (StringUtils.hasText(queueCapacity)) {
            builder.addPropertyValue("queueCapacity", queueCapacity);
        }
        //Configuration policy
        configureRejectionPolicy(element, builder);
        //Pool size attribute
        String poolSize = element.getAttribute("pool-size");
        if (StringUtils.hasText(poolSize)) {
            builder.addPropertyValue("poolSize", poolSize);
        }
    }

    //Configuration policy
    private void configureRejectionPolicy(Element element, BeanDefinitionBuilder builder) {
        //Rejection policy property
        String rejectionPolicy = element.getAttribute("rejection-policy");
        if (!StringUtils.hasText(rejectionPolicy)) {
            return;
        }
        String prefix = "java.util.concurrent.ThreadPoolExecutor.";
        String policyClassName;
        if (rejectionPolicy.equals("ABORT")) {
            policyClassName = prefix + "AbortPolicy";
        }
        else if (rejectionPolicy.equals("CALLER_RUNS")) {
            policyClassName = prefix + "CallerRunsPolicy";
        }
        else if (rejectionPolicy.equals("DISCARD")) {
            policyClassName = prefix + "DiscardPolicy";
        }
        else if (rejectionPolicy.equals("DISCARD_OLDEST")) {
            policyClassName = prefix + "DiscardOldestPolicy";
        }
        else {
            policyClassName = rejectionPolicy;
        }
        builder.addPropertyValue("rejectedExecutionHandler", new RootBeanDefinition(policyClassName));
    }

}

4.3. task:scheduled-tasks

ScheduledTasksBeanDefinitionParser
The main function of is parsing<task:scheduled-tasks/>Element to execute timer tasks

public class ScheduledTasksBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
    @Override
    protected String getBeanClassName(Element element) {
        //Use this class to implement beans
        return "org.springframework.scheduling.config.ContextLifecycleScheduledTaskRegistrar";
    }

    @Override
    protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
        //Cron task
        ManagedList<RuntimeBeanReference> cronTaskList = new ManagedList<>();
        //Fixed delay task
        ManagedList<RuntimeBeanReference> fixedDelayTaskList = new ManagedList<>();
        //Fixed frequency task
        ManagedList<RuntimeBeanReference> fixedRateTaskList = new ManagedList<>();
        //Trigger task
        ManagedList<RuntimeBeanReference> triggerTaskList = new ManagedList<>();

        //Traversal of child elements
        NodeList childNodes = element.getChildNodes();
        for (int i = 0; i < childNodes.getLength(); i++) {
            Node child = childNodes.item(i);

            Element taskElement = (Element) child;
            //Ref attribute
            String ref = taskElement.getAttribute("ref");
            //Method property
            String method = taskElement.getAttribute("method");

            // ...  Code omission

            //Cron attribute
            String cronAttribute = taskElement.getAttribute("cron");
            //Fixed delay attribute
            String fixedDelayAttribute = taskElement.getAttribute("fixed-delay");
            //Fixed rate attribute
            String fixedRateAttribute = taskElement.getAttribute("fixed-rate");
            //Trigger attribute
            String triggerAttribute = taskElement.getAttribute("trigger");
            //Initial delay attribute
            String initialDelayAttribute = taskElement.getAttribute("initial-delay");

            boolean hasCronAttribute = StringUtils.hasText(cronAttribute);
            boolean hasFixedDelayAttribute = StringUtils.hasText(fixedDelayAttribute);
            boolean hasFixedRateAttribute = StringUtils.hasText(fixedRateAttribute);
            boolean hasTriggerAttribute = StringUtils.hasText(triggerAttribute);
            boolean hasInitialDelayAttribute = StringUtils.hasText(initialDelayAttribute);

            // ...  Code omission

            //Use the class "org. Springframework. Scheduling. Support. Scheduledmethodrunnable"
            //Instantiate timer bean
            String runnableName =
                    runnableReference(ref, method, taskElement, parserContext).getBeanName();

            if (hasFixedDelayAttribute) {
                //Use the class "org. Springframework. Scheduling. Config. Intervaltask"
                //Instantiate fixed delay executor bean
                fixedDelayTaskList.add(intervalTaskReference(runnableName,
                        initialDelayAttribute, fixedDelayAttribute, taskElement, parserContext));
            }
            if (hasFixedRateAttribute) {
                //Use the class "org. Springframework. Scheduling. Config. Intervaltask"
                //Instantiate fixed frequency actuator bean
                fixedRateTaskList.add(intervalTaskReference(runnableName,
                        initialDelayAttribute, fixedRateAttribute, taskElement, parserContext));
            }
            if (hasCronAttribute) {
                //Use the class "org. Springframework. Scheduling. Config. Crontask"
                //Instantiate cron executor bean
                cronTaskList.add(cronTaskReference(runnableName, cronAttribute,
                        taskElement, parserContext));
            }
            if (hasTriggerAttribute) {
                //Use the class "org. Springframework. Scheduling. Config. Triggertask"
                //Instantiate trigger executor bean
                String triggerName = new RuntimeBeanReference(triggerAttribute).getBeanName();
                triggerTaskList.add(triggerTaskReference(runnableName, triggerName,
                        taskElement, parserContext));
            }
        }
        //Scheduler properties
        String schedulerRef = element.getAttribute("scheduler");
        if (StringUtils.hasText(schedulerRef)) {
            builder.addPropertyReference("taskScheduler", schedulerRef);
        }
        builder.addPropertyValue("cronTasksList", cronTaskList);
        builder.addPropertyValue("fixedDelayTasksList", fixedDelayTaskList);
        builder.addPropertyValue("fixedRateTasksList", fixedRateTaskList);
        builder.addPropertyValue("triggerTasksList", triggerTaskList);
    }
}

4.4. task:scheduler

SchedulerBeanDefinitionParser
The main function of is parsing<task:scheduler/>Element to configure the scheduling thread pool

public class SchedulerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
    @Override
    protected String getBeanClassName(Element element) {
        //Use this class to implement beans
        return "org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler";
    }

    @Override
    protected void doParse(Element element, BeanDefinitionBuilder builder) {
        //Pool size attribute
        String poolSize = element.getAttribute("pool-size");
        if (StringUtils.hasText(poolSize)) {
            builder.addPropertyValue("poolSize", poolSize);
        }
    }
}

5. CacheNamespaceHandler

public class CacheNamespaceHandler extends NamespaceHandlerSupport {
    @Override
    public void init() {
        registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenCacheBeanDefinitionParser());
        registerBeanDefinitionParser("advice", new CacheAdviceParser());
    }
}

5.1. cache:annotation-driven

AnnotationDrivenCacheBeanDefinitionParser
The main function of is parsing<cache:annotation-driven/>Element, supporting annotation@Cacheable@CacheEvict@CacheUpdate

class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser {
    @Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        //Mode attribute
        String mode = element.getAttribute("mode");
        //Use AspectJ to execute
        if ("aspectj".equals(mode)) {
            registerCacheAspect(element, parserContext);
        }
        //Use built-in functions to perform
        else {
            registerCacheAdvisor(element, parserContext);
        }

        return null;
    }

    //Use AspectJ to execute
    private void registerCacheAspect(Element element, ParserContext parserContext) {
        SpringCachingConfigurer.registerCacheAspect(element, parserContext);
    }

    //Use built-in functions to perform
    private void registerCacheAdvisor(Element element, ParserContext parserContext) {
        AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
        SpringCachingConfigurer.registerCacheAdvisor(element, parserContext);
    }

    //Resolve cache resolver attribute
    private static void parseCacheResolution(Element element, BeanDefinition def, boolean setBoth) {
        String name = element.getAttribute("cache-resolver");
        boolean hasText = StringUtils.hasText(name);
        if (hasText) {
            def.getPropertyValues().add("cacheResolver", new RuntimeBeanReference(name.trim()));
        }
        if (!hasText || setBoth) {
            def.getPropertyValues().add("cacheManager",
                    new RuntimeBeanReference(CacheNamespaceHandler.extractCacheManager(element)));
        }
    }
}

Inner classJCacheCachingConfigurer

private static class JCacheCachingConfigurer {
    //Use built-in functions to perform
    private static void registerCacheAdvisor(Element element, ParserContext parserContext) {
        //The bean "org. Springframework. Cache. Config. Internaljcacheadvisor" does not exist
        if (!parserContext.getRegistry().containsBeanDefinition(CacheManagementConfigUtils.JCACHE_ADVISOR_BEAN_NAME)) {
            Object source = parserContext.extractSource(element);

            //Create a bean executed by jcache
            BeanDefinition sourceDef = createJCacheOperationSourceBeanDefinition(element, source);
            //Get bean name
            String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);

            //Use "org. Springframework. Cache. Jcache. Interceptor. Jcacheinterceptor"
            //Create bean definition of cacheinterceptor
            RootBeanDefinition interceptorDef =
                    new RootBeanDefinition("org.springframework.cache.jcache.interceptor.JCacheInterceptor");

            // ...  Code omission

            //Get bean name
            String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);

            //Use "org.springframework.cache.jcache.interceptor.beanfactoryjcacheoperationsourceadvisor"
            //Create cacheadvisor definition
            RootBeanDefinition advisorDef = new RootBeanDefinition(
                    "org.springframework.cache.jcache.interceptor.BeanFactoryJCacheOperationSourceAdvisor");

            // ...  Code omission

            //Register the bean "org. Springframework. Cache. Config. Internaljcacheadvisor"
            parserContext.getRegistry().registerBeanDefinition(CacheManagementConfigUtils.JCACHE_ADVISOR_BEAN_NAME, advisorDef);

            //Register composite bean sourcedef + interceptordef + advisordef
            CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), source);
            compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
            compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
            compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, CacheManagementConfigUtils.JCACHE_ADVISOR_BEAN_NAME));
            parserContext.registerComponent(compositeDef);
        }
    }

    //Use AspectJ to execute
    private static void registerCacheAspect(Element element, ParserContext parserContext) {
        //The bean "org. Springframework. Cache. Config. Internaljcacheaspect" does not exist
        if (!parserContext.getRegistry().containsBeanDefinition(CacheManagementConfigUtils.JCACHE_ASPECT_BEAN_NAME)) {
            Object eleSource = parserContext.extractSource(element);
            RootBeanDefinition def = new RootBeanDefinition();

            //Use "org. Springframework. Cache. AspectJ. Jcachecacheaspect"
            //To create a bean
            def.setBeanClassName(JCACHE_ASPECT_CLASS_NAME);
            //Use factorymethod to initialize the bean
            def.setFactoryMethodName("aspectOf");
            //Create a bean executed by jcache
            BeanDefinition sourceDef = createJCacheOperationSourceBeanDefinition(element, eleSource);
            String sourceName =
                    parserContext.getReaderContext().registerWithGeneratedName(sourceDef);

            //Register the bean "org. Springframework. Cache. Jcache. Interceptor. Defaultjcacheoperationsource"
            parserContext.registerBeanComponent(new BeanComponentDefinition(sourceDef, sourceName));
            //Register the bean "org. Springframework. Cache. Config. Internaljcacheaspect"
            parserContext.registerBeanComponent(new BeanComponentDefinition(def, CacheManagementConfigUtils.JCACHE_ASPECT_BEAN_NAME));
        }
    }

    //Create a bean executed by jcache
    private static RootBeanDefinition createJCacheOperationSourceBeanDefinition(Element element, @Nullable Object eleSource) {
        //Use "org. Springframework. Cache. Jcache. Interceptor. Defaultjcacheoperationsource"“
        //To create a bean
        RootBeanDefinition sourceDef =
                new RootBeanDefinition("org.springframework.cache.jcache.interceptor.DefaultJCacheOperationSource");

        // ...  Code omission

        //Resolve cache resolver attribute
        CacheNamespaceHandler.parseKeyGenerator(element, sourceDef);
        return sourceDef;
    }
}

5.2. cache:advice

CacheAdviceParser
The main function of is parsing<cache:advice/>Element, configuring cache

class CacheAdviceParser extends AbstractSingleBeanDefinitionParser {
    @Override
    protected Class<?> getBeanClass(Element element) {
        //Use this class to implement beans
        return CacheInterceptor.class;
    }

    @Override
    protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
        //Cache manager attribute
        builder.addPropertyReference("cacheManager", CacheNamespaceHandler.extractCacheManager(element));

        //Caching element
        List<Element> cacheDefs = DomUtils.getChildElementsByTagName(element, DEFS_ELEMENT);
        //There is a caching element
        if (!cacheDefs.isEmpty()) {
            //Convert caching elements into beans
            List<RootBeanDefinition> attributeSourceDefinitions = parseDefinitionsSources(cacheDefs, parserContext);
            builder.addPropertyValue("cacheOperationSources", attributeSourceDefinitions);
        }
        else {
            //If there is no caching element, use "org. Springframework. Cache. Annotation. Annotationcacheoperationsource"
            //Create a default bean
            builder.addPropertyValue("cacheOperationSources",
                    new RootBeanDefinition("org.springframework.cache.annotation.AnnotationCacheOperationSource"));
        }
    }

    //Convert caching elements into beans
    private List<RootBeanDefinition> parseDefinitionsSources(List<Element> definitions, ParserContext parserContext) {
        ManagedList<RootBeanDefinition> defs = new ManagedList<>(definitions.size());

        //Traversal
        for (Element element : definitions) {
            defs.add(parseDefinitionSource(element, parserContext));
        }

        return defs;
    }

    //Convert caching elements into beans
    private RootBeanDefinition parseDefinitionSource(Element definition, ParserContext parserContext) {
        // ...  Code omission
    }
}

6. MvcNamespaceHandler

public class MvcNamespaceHandler extends NamespaceHandlerSupport {
    @Override
    public void init() {
        registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
        registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());
        registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
        registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
        registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
        registerBeanDefinitionParser("redirect-view-controller", new ViewControllerBeanDefinitionParser());
        registerBeanDefinitionParser("status-controller", new ViewControllerBeanDefinitionParser());
        registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser());
        registerBeanDefinitionParser("tiles-configurer", new TilesConfigurerBeanDefinitionParser());
        registerBeanDefinitionParser("freemarker-configurer", new FreeMarkerConfigurerBeanDefinitionParser());
        registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser());
        registerBeanDefinitionParser("script-template-configurer", new ScriptTemplateConfigurerBeanDefinitionParser());
        registerBeanDefinitionParser("cors", new CorsBeanDefinitionParser());
    }
}

mvcThere are many processors in the namespace. Only the first one is resolved heremvc:annotation-driven, others who are interested can explore by themselves

AnnotationDrivenBeanDefinitionParser
The main function of is parsing<mvc:annotation-driven/>Element, enable annotation driven, throughcontext:component-scanLabel configuration, automatic scanning
@Component,@Controller,@Service,@RepositoryComponents marked with annotations are registered in the factory to process the request

class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
    @Override
    public BeanDefinition parse(Element element, ParserContext context) {
        //Meta information
        Object source = context.extractSource(element);
        XmlReaderContext readerContext = context.getReaderContext();

        // ...  Code omission

        //Request mapping processor bean
        RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);

        // ...  Code omission

        //Enable matrix variables property
        if (element.hasAttribute("enable-matrix-variables")) {
            boolean enableMatrixVariables = Boolean.parseBoolean(element.getAttribute("enable-matrix-variables"));
            handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);
        }

        //Configure path mapping
        configurePathMatchingProperties(handlerMappingDef, element, context);
        //Register requestmappinghandlermapping class bean
        readerContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME, handlerMappingDef);

        // ...  Code omission

        //Get data conversion service
        RuntimeBeanReference conversionService = getConversionService(element, source, context);
        //Get validator
        RuntimeBeanReference validator = getValidator(element, source, context);
        //Get text parser
        RuntimeBeanReference messageCodesResolver = getMessageCodesResolver(element);

        //Register webinitializebindizer.webinitializer class bean
        RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);

        // ...  Code omission

        //Load conversionservice, validator, messagecodesresolver
        bindingDef.getPropertyValues().add("conversionService", conversionService);
        bindingDef.getPropertyValues().add("validator", validator);
        bindingDef.getPropertyValues().add("messageCodesResolver", messageCodesResolver);

        //Configure message converter
        ManagedList<?> messageConverters = getMessageConverters(element, source, context);
        //Custom parameter resolver configured by argument resolvers sub element
        ManagedList<?> argumentResolvers = getArgumentResolvers(element, context);
        //Custom response parser configured by return value handlers sub element
        ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, context);
        //Asynchronous task timeout configured by async support sub element
        String asyncTimeout = getAsyncTimeout(element);
        //Asynchronous task executor configured by async support sub element
        RuntimeBeanReference asyncExecutor = getAsyncExecutor(element);
        //Callable interceptors request interceptor configured by async support sub element
        ManagedList<?> callableInterceptors = getInterceptors(element, source, context, "callable-interceptors");
        //Deferred result interceptors response interceptor configured by async support sub element
        ManagedList<?> deferredResultInterceptors = getInterceptors(element, source, context, "deferred-result-interceptors");

        //Register requestmappinghandleradapter class bean
        RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
        //Load contentnegotiationmanager, bindingdef, messageconverters
        handlerAdapterDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
        handlerAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
        handlerAdapterDef.getPropertyValues().add("messageConverters", messageConverters);
        //Load Jackson request processing
        addRequestBodyAdvice(handlerAdapterDef);
        //Loading Jackson response processing
        addResponseBodyAdvice(handlerAdapterDef);

        //Ignore default model on redirect attribute
        if (element.hasAttribute("ignore-default-model-on-redirect")) {
            Boolean ignoreDefaultModel = Boolean.valueOf(element.getAttribute("ignore-default-model-on-redirect"));
            handlerAdapterDef.getPropertyValues().add("ignoreDefaultModelOnRedirect", ignoreDefaultModel);
        }
        if (argumentResolvers != null) {
            handlerAdapterDef.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
        }
        if (returnValueHandlers != null) {
            handlerAdapterDef.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);
        }
        if (asyncTimeout != null) {
            handlerAdapterDef.getPropertyValues().add("asyncRequestTimeout", asyncTimeout);
        }
        if (asyncExecutor != null) {
            handlerAdapterDef.getPropertyValues().add("taskExecutor", asyncExecutor);
        }

        handlerAdapterDef.getPropertyValues().add("callableInterceptors", callableInterceptors);
        handlerAdapterDef.getPropertyValues().add("deferredResultInterceptors", deferredResultInterceptors);

        //Register requestmappinghandleradapter class bean
        readerContext.getRegistry().registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME, handlerAdapterDef);

        //Register compositeuricomponentscontributorfactorybean class bean
        RootBeanDefinition uriContributorDef =
                new RootBeanDefinition(CompositeUriComponentsContributorFactoryBean.class);
        uriContributorDef.setSource(source);
        uriContributorDef.getPropertyValues().addPropertyValue("handlerAdapter", handlerAdapterDef);
        uriContributorDef.getPropertyValues().addPropertyValue("conversionService", conversionService);

        //Register mvcuricomponentscontributor bean
        String uriContributorName = MvcUriComponentsBuilder.MVC_URI_COMPONENTS_CONTRIBUTOR_BEAN_NAME;
        readerContext.getRegistry().registerBeanDefinition(uriContributorName, uriContributorDef);

        //Register conversionserviceexposinginterceptor class bean
        RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class);
        csInterceptorDef.setSource(source);
        csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService);

        //Register mappedinterceptor class bean
        RootBeanDefinition mappedInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);

        // ...  Code omission

        //Register exceptionhandlerexceptionresolver class bean
        RootBeanDefinition methodExceptionResolver = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class);

        // ...  Code omission

        //Register responsestatusexceptionresolver class bean
        RootBeanDefinition statusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class);

        // ...  Code omission

        //Register defaulthandlerexceptionresolver class bean
        RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class);

        // ...  Code omission

        //Register a series of beans
        context.registerComponent(new BeanComponentDefinition(handlerMappingDef, HANDLER_MAPPING_BEAN_NAME));
        context.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME));
        context.registerComponent(new BeanComponentDefinition(uriContributorDef, uriContributorName));
        context.registerComponent(new BeanComponentDefinition(mappedInterceptorDef, mappedInterceptorName));
        context.registerComponent(new BeanComponentDefinition(methodExceptionResolver, methodExResolverName));
        context.registerComponent(new BeanComponentDefinition(statusExceptionResolver, statusExResolverName));
        context.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExResolverName));

        // ...  Code omission

        context.popAndRegisterContainingComponent();

        return null;
    }
}
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
    //Configure path mapping
    private void configurePathMatchingProperties(
            RootBeanDefinition handlerMappingDef, Element element, ParserContext context) {
        //Get path matching child element
        Element pathMatchingElement = DomUtils.getChildElementByTagName(element, "path-matching");
        if (pathMatchingElement != null) {
            Object source = context.extractSource(element);

            //Suffix pattern attribute
            if (pathMatchingElement.hasAttribute("suffix-pattern")) {
                Boolean useSuffixPatternMatch = Boolean.valueOf(pathMatchingElement.getAttribute("suffix-pattern"));
                handlerMappingDef.getPropertyValues().add("useSuffixPatternMatch", useSuffixPatternMatch);
            }
            //Trailing slash property
            if (pathMatchingElement.hasAttribute("trailing-slash")) {
                Boolean useTrailingSlashMatch = Boolean.valueOf(pathMatchingElement.getAttribute("trailing-slash"));
                handlerMappingDef.getPropertyValues().add("useTrailingSlashMatch", useTrailingSlashMatch);
            }
            //Registered suffixes only attribute
            if (pathMatchingElement.hasAttribute("registered-suffixes-only")) {
                Boolean useRegisteredSuffixPatternMatch = Boolean.valueOf(pathMatchingElement.getAttribute("registered-suffixes-only"));
                handlerMappingDef.getPropertyValues().add("useRegisteredSuffixPatternMatch", useRegisteredSuffixPatternMatch);
            }

            RuntimeBeanReference pathHelperRef = null;
            //Path helper attribute
            if (pathMatchingElement.hasAttribute("path-helper")) {
                pathHelperRef = new RuntimeBeanReference(pathMatchingElement.getAttribute("path-helper"));
            }
            pathHelperRef = MvcNamespaceUtils.registerUrlPathHelper(pathHelperRef, context, source);
            handlerMappingDef.getPropertyValues().add("urlPathHelper", pathHelperRef);

            RuntimeBeanReference pathMatcherRef = null;
            //Path matcher attribute
            if (pathMatchingElement.hasAttribute("path-matcher")) {
                pathMatcherRef = new RuntimeBeanReference(pathMatchingElement.getAttribute("path-matcher"));
            }
            pathMatcherRef = MvcNamespaceUtils.registerPathMatcher(pathMatcherRef, context, source);
            handlerMappingDef.getPropertyValues().add("pathMatcher", pathMatcherRef);
        }
    }

    //Get data conversion service
    private RuntimeBeanReference getConversionService(Element element, @Nullable Object source, ParserContext context) {
        RuntimeBeanReference conversionServiceRef;
        //The conversion service attribute is configured
        if (element.hasAttribute("conversion-service")) {
            conversionServiceRef = new RuntimeBeanReference(element.getAttribute("conversion-service"));
        }
        else {
            //If not, create a default with formattingconversionservicefactorybean
            RootBeanDefinition conversionDef = new RootBeanDefinition(FormattingConversionServiceFactoryBean.class);

            // ...  Code omission

            conversionServiceRef = new RuntimeBeanReference(conversionName);
        }
        return conversionServiceRef;
    }

    //Get validator
    private RuntimeBeanReference getValidator(Element element, @Nullable Object source, ParserContext context) {
        //Validator attribute is configured
        if (element.hasAttribute("validator")) {
            return new RuntimeBeanReference(element.getAttribute("validator"));
        }
        else if (javaxValidationPresent) {
            //If not, create a default with optionalvalidatorfactorybean
            RootBeanDefinition validatorDef = new RootBeanDefinition(
                    "org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean");

            // ...  Code omission

            return new RuntimeBeanReference(validatorName);
        }
        else {
            return null;
        }
    }

    //Get text parser
    private RuntimeBeanReference getMessageCodesResolver(Element element) {
        //The message codes resolver attribute is configured
        if (element.hasAttribute("message-codes-resolver")) {
            return new RuntimeBeanReference(element.getAttribute("message-codes-resolver"));
        }
        else {
            return null;
        }
    }
}
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
    //Configure message converter
    private ManagedList<?> getMessageConverters(Element element, @Nullable Object source, ParserContext context) {
        //Message converters child element
        Element convertersElement = DomUtils.getChildElementByTagName(element, "message-converters");
        //Result set
        ManagedList<Object> messageConverters = new ManagedList<>();

        //There are message converters child elements
        if (convertersElement != null) {
            //Convert the bean and ref sub elements into beans and add them to the result set
            for (Element beanElement : DomUtils.getChildElementsByTagName(convertersElement, "bean", "ref")) {
                Object object = context.getDelegate().parsePropertySubElement(beanElement, null);
                messageConverters.add(object);
            }
        }

        //There are message converters child elements,但有register-defaults属性
        if (convertersElement == null || Boolean.parseBoolean(convertersElement.getAttribute("register-defaults"))) {
            //Add bytearrayhttpmessageconverter Class bean to result set
            //Byte array converter
            messageConverters.add(createConverterDefinition(ByteArrayHttpMessageConverter.class, source));

            //Add stringhttpmessageconverter Class bean to result set
            //Character converter
            RootBeanDefinition stringConverterDef = createConverterDefinition(StringHttpMessageConverter.class, source);
            stringConverterDef.getPropertyValues().add("writeAcceptCharset", false);
            messageConverters.add(stringConverterDef);

            //Add resourcehttpmessageconverter Class bean to result set
            //Resource converter
            messageConverters.add(createConverterDefinition(ResourceHttpMessageConverter.class, source));
            //Add resourceregionhttpmessageconverter Class bean to result set
            //Resource area converter
            messageConverters.add(createConverterDefinition(ResourceRegionHttpMessageConverter.class, source));
            //Add sourcehttpmessageconverter Class bean to result set
            // javax. xml. transform. Source converter
            messageConverters.add(createConverterDefinition(SourceHttpMessageConverter.class, source));
            //Add allencompassingformhttpmessageconverter Class bean to result set
            //Form data converter
            messageConverters.add(createConverterDefinition(AllEncompassingFormHttpMessageConverter.class, source));

            // ...  Code omission

            if (jackson2XmlPresent) {
                //Add jackson2xml converter
            }

            // ...  Code omission

            if (jackson2Present) {
                //Add jackson2 converter
            }
            else if (gsonPresent) {
                //Add gson converter
            }

            // ...  Code omission
        }
        return messageConverters;
    }
}

follow-up

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

Author:Deep (@ senntyou)

Copyright notice: free reproduction – non commercial – non derivative – keep signature(Creative sharing 3.0 License