Spring 源码解析八:Xml 配置中默认的命名空间处理器
在 Spring 源码解析五:Bean 的配置、定义、注册 中,有一些 Xml 配置中默认的命名空间处理器还未解析
- SimpleConstructorNamespaceHandler
- SimplePropertyNamespaceHandler
- UtilNamespaceHandler
- ContextNamespaceHandler
- JeeNamespaceHandler
- LangNamespaceHandler
- TaskNamespaceHandler
- CacheNamespaceHandler
- MvcNamespaceHandler
- AopNamespaceHandler
- JdbcNamespaceHandler
- TxNamespaceHandler
这里只解析罕用的几个
SimpleConstructorNamespaceHandler
SimplePropertyNamespaceHandler
ContextNamespaceHandler
TaskNamespaceHandler
CacheNamespaceHandler
MvcNamespaceHandler
其余的有趣味能够自行摸索
1. SimpleConstructorNamespaceHandler
SimpleConstructorNamespaceHandler
的次要性能是在实例化如下配置的 bean
<bean id="author" class="..TestBean" c:name="Enescu" c:work-ref="compositions"/>
将 name="Enescu", work=bean[compositions]
作为构造函数的参数实例化 bean
public class SimpleConstructorNamespaceHandler implements NamespaceHandler {
@Override
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {if (node instanceof Attr) {Attr attr = (Attr) node;
// 去除两边空白
String argName = StringUtils.trimWhitespace(parserContext.getDelegate().getLocalName(attr));
// 去除两边空白
String argValue = StringUtils.trimWhitespace(attr.getValue());
// 结构函数参数汇合
ConstructorArgumentValues cvs = definition.getBeanDefinition().getConstructorArgumentValues();
boolean ref = false;
// 如果字段名以 "-ref" 后果,则示意在运行时对其余 bean 的援用
if (argName.endsWith(REF_SUFFIX)) {
ref = true;
argName = argName.substring(0, argName.length() - REF_SUFFIX.length());
}
// 用 ValueHolder 封装值
ValueHolder valueHolder = new ValueHolder(ref ? new RuntimeBeanReference(argValue) : argValue);
valueHolder.setSource(parserContext.getReaderContext().extractSource(attr));
// 以 "_" 结尾的,示意是没有名字的参数,依照程序传入就能够了
if (argName.startsWith(DELIMITER_PREFIX)) {String arg = argName.substring(1).trim();
// 如果没有指定程序,间接增加
if (!StringUtils.hasText(arg)) {cvs.addGenericArgumentValue(valueHolder);
}
// 如果有指定程序,指定程序增加
else {
int index = -1;
try {index = Integer.parseInt(arg);
}
catch (NumberFormatException ex) {// ... 代码省略}
// ... 代码省略
// 增加进 cvs
cvs.addIndexedArgumentValue(index, valueHolder);
}
}
// 有名字的参数
else {
// ... 代码省略
// 增加进 cvs
valueHolder.setName(Conventions.attributeNameToPropertyName(argName));
cvs.addGenericArgumentValue(valueHolder);
}
}
return definition;
}
}
2. SimplePropertyNamespaceHandler
SimplePropertyNamespaceHandler
的次要性能是在实例化如下配置的 bean
<bean id="rob" class="..TestBean" p:name="Rob Harrop" p:spouse-ref="sally"/>
将 name="Rob Harrop", spouse=bean[sally]
作为属性注入到 bean 中
public class SimplePropertyNamespaceHandler implements NamespaceHandler {
@Override
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {if (node instanceof Attr) {Attr attr = (Attr) node;
// 属性名
String propertyName = parserContext.getDelegate().getLocalName(attr);
// 属性值
String propertyValue = attr.getValue();
// 属性汇合
MutablePropertyValues pvs = definition.getBeanDefinition().getPropertyValues();
// 如果字段名以 "-ref" 后果,则示意在运行时对其余 bean 的援用
if (propertyName.endsWith(REF_SUFFIX)) {propertyName = propertyName.substring(0, propertyName.length() - REF_SUFFIX.length());
// 把字段名从短横线 - 或下划线_式的,转化为驼峰式的
pvs.add(Conventions.attributeNameToPropertyName(propertyName), new RuntimeBeanReference(propertyValue));
}
else {
// 把字段名从短横线 - 或下划线_式的,转化为驼峰式的
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
的次要性能是解析 <context:property-placeholder/>
元素,在 bean 定义时,应用 ${}
援用内部起源的属性
先看看继承关系
- AbstractBeanDefinitionParser
- AbstractSingleBeanDefinitionParser
- AbstractPropertyLoadingBeanDefinitionParser
- PropertyPlaceholderBeanDefinitionParser
3.1.1. AbstractBeanDefinitionParser
AbstractBeanDefinitionParser
的次要性能是实现了 BeanDefinitionParser
接口的 parse
办法,提供了根本的由配置解析为对象的性能
public abstract class AbstractBeanDefinitionParser implements BeanDefinitionParser {
@Override
public final BeanDefinition parse(Element element, ParserContext parserContext) {
// 解析元素
AbstractBeanDefinition definition = parseInternal(element, parserContext);
try {
// 获取 bean 的 id
String id = resolveId(element, definition, parserContext);
String[] aliases = null;
// 获取 name 属性,用逗号分隔为多个别名
if (shouldParseNameAsAliases()) {String name = element.getAttribute(NAME_ATTRIBUTE);
if (StringUtils.hasLength(name)) {aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
}
}
// 封装为 BeanDefinitionHolder
BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
// 注册到 registry 中
registerBeanDefinition(holder, parserContext.getRegistry());
// ... 代码省略
}
catch (BeanDefinitionStoreException ex) {// ... 代码省略}
return definition;
}
// 解析元素,由子类实现
protected abstract AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext);
// 获取 bean 的 id,先获取 id 属性,其次 name 属性,都没有,生成默认的名字
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
throws BeanDefinitionStoreException {// ... 代码省略}
}
3.1.2. AbstractSingleBeanDefinitionParser
AbstractSingleBeanDefinitionParser
的次要性能是反对解析为单例的 bean
public abstract class AbstractSingleBeanDefinitionParser extends AbstractBeanDefinitionParser {
@Override
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
// 创立一个结构器
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
// 父元素
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);
}
}
// ... 代码省略
// 解析到结构器
doParse(element, parserContext, builder);
return builder.getBeanDefinition();}
// 解析到结构器,由子类实现
protected void doParse(Element element, BeanDefinitionBuilder builder) {}}
3.1.3. AbstractPropertyLoadingBeanDefinitionParser
AbstractPropertyLoadingBeanDefinitionParser
的次要性能是解析 context:property-...
元素
abstract class AbstractPropertyLoadingBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
// location 属性
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 属性
String propertiesRef = element.getAttribute("properties-ref");
if (StringUtils.hasLength(propertiesRef)) {builder.addPropertyReference("properties", propertiesRef);
}
// file-encoding 属性
String fileEncoding = element.getAttribute("file-encoding");
if (StringUtils.hasLength(fileEncoding)) {builder.addPropertyValue("fileEncoding", fileEncoding);
}
// order 属性
String order = element.getAttribute("order");
if (StringUtils.hasLength(order)) {builder.addPropertyValue("order", Integer.valueOf(order));
}
// ignore-resource-not-found 属性
builder.addPropertyValue("ignoreResourceNotFound",
Boolean.valueOf(element.getAttribute("ignore-resource-not-found")));
// local-override 属性
builder.addPropertyValue("localOverride",
Boolean.valueOf(element.getAttribute("local-override")));
}
}
3.1.4. PropertyPlaceholderBeanDefinitionParser
PropertyPlaceholderBeanDefinitionParser
的次要性能是解析 context:property-placeholder
元素
class PropertyPlaceholderBeanDefinitionParser extends AbstractPropertyLoadingBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {
// 应用这个类来实现 bean
return org.springframework.beans.factory.config.PropertyPlaceholderConfigurer.class;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {super.doParse(element, parserContext, builder);
// ignore-unresolvable 属性
builder.addPropertyValue("ignoreUnresolvablePlaceholders",
Boolean.valueOf(element.getAttribute("ignore-unresolvable")));
// system-properties-mode 属性
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 属性
if (element.hasAttribute("value-separator")) {builder.addPropertyValue("valueSeparator", element.getAttribute("value-separator"));
}
// trim-values 属性
if (element.hasAttribute("trim-values")) {builder.addPropertyValue("trimValues", element.getAttribute("trim-values"));
}
// null-value 属性
if (element.hasAttribute("null-value")) {builder.addPropertyValue("nullValue", element.getAttribute("null-value"));
}
}
}
3.2. context:property-override
PropertyOverrideBeanDefinitionParser
的次要性能是解析 <context:property-override/>
元素,为 xml 配置文件中的 bean 的属性指定最终后果
class PropertyOverrideBeanDefinitionParser extends AbstractPropertyLoadingBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {
// 应用这个类来实现 bean
return PropertyOverrideConfigurer.class;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {super.doParse(element, parserContext, builder);
// ignore-unresolvable 属性
builder.addPropertyValue("ignoreInvalidKeys",
Boolean.valueOf(element.getAttribute("ignore-unresolvable")));
}
}
3.3. context:annotation-config
AnnotationConfigBeanDefinitionParser
的次要性能是解析 <context:annotation-config/>
元素,应用 @Autowired
主动拆卸 bean
public class AnnotationConfigBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {Object source = parserContext.extractSource(element);
// 获取 registry 所有相干的 bean 定义
Set<BeanDefinitionHolder> processorDefinitions =
AnnotationConfigUtils.registerAnnotationConfigProcessors(parserContext.getRegistry(), source);
// ... 代码省略
// 注册 bean 定义
for (BeanDefinitionHolder processorDefinition : processorDefinitions) {parserContext.registerComponent(new BeanComponentDefinition(processorDefinition));
}
// ... 代码省略
return null;
}
}
3.4. context:component-scan
ComponentScanBeanDefinitionParser
的次要性能是解析 <context:component-scan/>
元素,主动扫描指定包下的注解 bean
public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
// base-package 属性
String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
// 分隔多个包
String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
// 创立并配置扫描对象
ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
// 扫描包中的组件
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
// 注册组件到上下文中
registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
return null;
}
}
对于 context:
命令空间的解析就到这里了,其余的有趣味能够自行摸索
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
的次要性能是解析 <task:annotation-driven/>
元素,开启定时器开关,主动扫描程序中带注解的定时器
public class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {Object source = parserContext.extractSource(element);
// ... 代码省略
// 获取 registry
BeanDefinitionRegistry registry = parserContext.getRegistry();
// mode 属性
String mode = element.getAttribute("mode");
// 应用 aspectj 来执行异步工作
if ("aspectj".equals(mode)) {
// mode="aspectj"
registerAsyncExecutionAspect(element, parserContext);
}
// 应用内置的性能来执行异步工作
else {
// bean "org.springframework.context.annotation.internalAsyncAnnotationProcessor" 曾经存在
if (registry.containsBeanDefinition(TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)) {// ... 代码省略}
else {
// 应用类 "org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor"
// 来配置 bean "org.springframework.context.annotation.internalAsyncAnnotationProcessor"
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition("org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor");
builder.getRawBeanDefinition().setSource(source);
// executor 属性
String executor = element.getAttribute("executor");
if (StringUtils.hasText(executor)) {builder.addPropertyReference("executor", executor);
}
// exception-handler 属性
String exceptionHandler = element.getAttribute("exception-handler");
if (StringUtils.hasText(exceptionHandler)) {builder.addPropertyReference("exceptionHandler", exceptionHandler);
}
// proxy-target-class 属性
if (Boolean.parseBoolean(element.getAttribute(AopNamespaceUtils.PROXY_TARGET_CLASS_ATTRIBUTE))) {builder.addPropertyValue("proxyTargetClass", true);
}
// 注册组件到 registry 与上下文
registerPostProcessor(parserContext, builder, TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME);
}
}
// bean "org.springframework.context.annotation.internalScheduledAnnotationProcessor" 曾经存在
if (registry.containsBeanDefinition(TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)) {// ... 代码省略}
else {
// 应用类 "org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor"
// 来配置 bean "org.springframework.context.annotation.internalScheduledAnnotationProcessor"
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition("org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor");
builder.getRawBeanDefinition().setSource(source);
// scheduler 属性
String scheduler = element.getAttribute("scheduler");
if (StringUtils.hasText(scheduler)) {builder.addPropertyReference("scheduler", scheduler);
}
// 注册组件到 registry 与上下文
registerPostProcessor(parserContext, builder, TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME);
}
// ... 代码省略
return null;
}
// 应用 aspectj 来执行异步工作
private void registerAsyncExecutionAspect(Element element, ParserContext parserContext) {
// bean "org.springframework.scheduling.config.internalAsyncExecutionAspect" 不存在
if (!parserContext.getRegistry().containsBeanDefinition(TaskManagementConfigUtils.ASYNC_EXECUTION_ASPECT_BEAN_NAME)) {
// 应用类 "org.springframework.scheduling.aspectj.AnnotationAsyncExecutionAspect"
// 来配置 bean "org.springframework.scheduling.config.internalAsyncExecutionAspect"
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ASYNC_EXECUTION_ASPECT_CLASS_NAME);
// 应用 FactoryMethod 来初始化 bean
builder.setFactoryMethod("aspectOf");
// executor 属性
String executor = element.getAttribute("executor");
if (StringUtils.hasText(executor)) {builder.addPropertyReference("executor", executor);
}
// exception-handler 属性
String exceptionHandler = element.getAttribute("exception-handler");
if (StringUtils.hasText(exceptionHandler)) {builder.addPropertyReference("exceptionHandler", exceptionHandler);
}
// 注册 bean
parserContext.registerBeanComponent(new BeanComponentDefinition(builder.getBeanDefinition(),
TaskManagementConfigUtils.ASYNC_EXECUTION_ASPECT_BEAN_NAME));
}
}
}
4.2. task:executor
ExecutorBeanDefinitionParser
的次要性能是解析 <task:executor/>
元素,用于配置工作执行器
public class ExecutorBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected String getBeanClassName(Element element) {
// 应用这个类来实现 bean
return "org.springframework.scheduling.config.TaskExecutorFactoryBean";
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
// keep-alive 属性
String keepAliveSeconds = element.getAttribute("keep-alive");
if (StringUtils.hasText(keepAliveSeconds)) {builder.addPropertyValue("keepAliveSeconds", keepAliveSeconds);
}
// queue-capacity 属性
String queueCapacity = element.getAttribute("queue-capacity");
if (StringUtils.hasText(queueCapacity)) {builder.addPropertyValue("queueCapacity", queueCapacity);
}
// 配置策略
configureRejectionPolicy(element, builder);
// pool-size 属性
String poolSize = element.getAttribute("pool-size");
if (StringUtils.hasText(poolSize)) {builder.addPropertyValue("poolSize", poolSize);
}
}
// 配置策略
private void configureRejectionPolicy(Element element, BeanDefinitionBuilder builder) {
// rejection-policy 属性
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
的次要性能是解析 <task:scheduled-tasks/>
元素,执行定时器工作
public class ScheduledTasksBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected String getBeanClassName(Element element) {
// 应用这个类来实现 bean
return "org.springframework.scheduling.config.ContextLifecycleScheduledTaskRegistrar";
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
// cron 工作
ManagedList<RuntimeBeanReference> cronTaskList = new ManagedList<>();
// 固定提早工作
ManagedList<RuntimeBeanReference> fixedDelayTaskList = new ManagedList<>();
// 固定频率工作
ManagedList<RuntimeBeanReference> fixedRateTaskList = new ManagedList<>();
// 触发工作
ManagedList<RuntimeBeanReference> triggerTaskList = new ManagedList<>();
// 遍历子元素
NodeList childNodes = element.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {Node child = childNodes.item(i);
Element taskElement = (Element) child;
// ref 属性
String ref = taskElement.getAttribute("ref");
// method 属性
String method = taskElement.getAttribute("method");
// ... 代码省略
// cron 属性
String cronAttribute = taskElement.getAttribute("cron");
// fixed-delay 属性
String fixedDelayAttribute = taskElement.getAttribute("fixed-delay");
// fixed-rate 属性
String fixedRateAttribute = taskElement.getAttribute("fixed-rate");
// trigger 属性
String triggerAttribute = taskElement.getAttribute("trigger");
// initial-delay 属性
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);
// ... 代码省略
// 应用类 "org.springframework.scheduling.support.ScheduledMethodRunnable"
// 实例化定时器 bean
String runnableName =
runnableReference(ref, method, taskElement, parserContext).getBeanName();
if (hasFixedDelayAttribute) {
// 应用类 "org.springframework.scheduling.config.IntervalTask"
// 实例化固定提早执行器 bean
fixedDelayTaskList.add(intervalTaskReference(runnableName,
initialDelayAttribute, fixedDelayAttribute, taskElement, parserContext));
}
if (hasFixedRateAttribute) {
// 应用类 "org.springframework.scheduling.config.IntervalTask"
// 实例化固定频率执行器 bean
fixedRateTaskList.add(intervalTaskReference(runnableName,
initialDelayAttribute, fixedRateAttribute, taskElement, parserContext));
}
if (hasCronAttribute) {
// 应用类 "org.springframework.scheduling.config.CronTask"
// 实例化 cron 执行器 bean
cronTaskList.add(cronTaskReference(runnableName, cronAttribute,
taskElement, parserContext));
}
if (hasTriggerAttribute) {
// 应用类 "org.springframework.scheduling.config.TriggerTask"
// 实例化触发执行器 bean
String triggerName = new RuntimeBeanReference(triggerAttribute).getBeanName();
triggerTaskList.add(triggerTaskReference(runnableName, triggerName,
taskElement, parserContext));
}
}
// scheduler 属性
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
的次要性能是解析 <task:scheduler/>
元素,配置调度线程池
public class SchedulerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected String getBeanClassName(Element element) {
// 应用这个类来实现 bean
return "org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler";
}
@Override
protected void doParse(Element element, BeanDefinitionBuilder builder) {
// pool-size 属性
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
的次要性能是解析 <cache:annotation-driven/>
元素,反对注解注 @Cacheable
、@CacheEvict
、@CacheUpdate
class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
// mode 属性
String mode = element.getAttribute("mode");
// 应用 aspectj 来执行
if ("aspectj".equals(mode)) {registerCacheAspect(element, parserContext);
}
// 应用内置的性能来执行
else {registerCacheAdvisor(element, parserContext);
}
return null;
}
// 应用 aspectj 来执行
private void registerCacheAspect(Element element, ParserContext parserContext) {SpringCachingConfigurer.registerCacheAspect(element, parserContext);
}
// 应用内置的性能来执行
private void registerCacheAdvisor(Element element, ParserContext parserContext) {AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
SpringCachingConfigurer.registerCacheAdvisor(element, parserContext);
}
// 解析 cache-resolver 属性
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)));
}
}
}
外部类 JCacheCachingConfigurer
private static class JCacheCachingConfigurer {
// 应用内置的性能来执行
private static void registerCacheAdvisor(Element element, ParserContext parserContext) {
// bean "org.springframework.cache.config.internalJCacheAdvisor" 不存在
if (!parserContext.getRegistry().containsBeanDefinition(CacheManagementConfigUtils.JCACHE_ADVISOR_BEAN_NAME)) {Object source = parserContext.extractSource(element);
// 创立一个 JCache 执行的 bean
BeanDefinition sourceDef = createJCacheOperationSourceBeanDefinition(element, source);
// 获取 bean 名字
String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
// 应用 "org.springframework.cache.jcache.interceptor.JCacheInterceptor"
// 创立 CacheInterceptor 的 bean 定义
RootBeanDefinition interceptorDef =
new RootBeanDefinition("org.springframework.cache.jcache.interceptor.JCacheInterceptor");
// ... 代码省略
// 获取 bean 名字
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
// 应用 "org.springframework.cache.jcache.interceptor.BeanFactoryJCacheOperationSourceAdvisor"
// 创立 CacheAdvisor 定义
RootBeanDefinition advisorDef = new RootBeanDefinition("org.springframework.cache.jcache.interceptor.BeanFactoryJCacheOperationSourceAdvisor");
// ... 代码省略
// 注册 bean "org.springframework.cache.config.internalJCacheAdvisor"
parserContext.getRegistry().registerBeanDefinition(CacheManagementConfigUtils.JCACHE_ADVISOR_BEAN_NAME, advisorDef);
// 注册复合 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);
}
}
// 应用 aspectj 来执行
private static void registerCacheAspect(Element element, ParserContext parserContext) {
// bean "org.springframework.cache.config.internalJCacheAspect" 不存在
if (!parserContext.getRegistry().containsBeanDefinition(CacheManagementConfigUtils.JCACHE_ASPECT_BEAN_NAME)) {Object eleSource = parserContext.extractSource(element);
RootBeanDefinition def = new RootBeanDefinition();
// 应用 "org.springframework.cache.aspectj.JCacheCacheAspect"
// 来创立 bean
def.setBeanClassName(JCACHE_ASPECT_CLASS_NAME);
// 应用 FactoryMethod 来初始化 bean
def.setFactoryMethodName("aspectOf");
// 创立一个 JCache 执行的 bean
BeanDefinition sourceDef = createJCacheOperationSourceBeanDefinition(element, eleSource);
String sourceName =
parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
// 注册 bean "org.springframework.cache.jcache.interceptor.DefaultJCacheOperationSource"
parserContext.registerBeanComponent(new BeanComponentDefinition(sourceDef, sourceName));
// 注册 bean "org.springframework.cache.config.internalJCacheAspect"
parserContext.registerBeanComponent(new BeanComponentDefinition(def, CacheManagementConfigUtils.JCACHE_ASPECT_BEAN_NAME));
}
}
// 创立一个 JCache 执行的 bean
private static RootBeanDefinition createJCacheOperationSourceBeanDefinition(Element element, @Nullable Object eleSource) {
// 应用 "org.springframework.cache.jcache.interceptor.DefaultJCacheOperationSource""
// 来创立 bean
RootBeanDefinition sourceDef =
new RootBeanDefinition("org.springframework.cache.jcache.interceptor.DefaultJCacheOperationSource");
// ... 代码省略
// 解析 cache-resolver 属性
CacheNamespaceHandler.parseKeyGenerator(element, sourceDef);
return sourceDef;
}
}
5.2. cache:advice
CacheAdviceParser
的次要性能是解析 <cache:advice/>
元素,配置缓存
class CacheAdviceParser extends AbstractSingleBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {
// 应用这个类来实现 bean
return CacheInterceptor.class;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
// cache-manager 属性
builder.addPropertyReference("cacheManager", CacheNamespaceHandler.extractCacheManager(element));
// caching 元素
List<Element> cacheDefs = DomUtils.getChildElementsByTagName(element, DEFS_ELEMENT);
// 有 caching 元素
if (!cacheDefs.isEmpty()) {
// 把 caching 元素转化成 bean
List<RootBeanDefinition> attributeSourceDefinitions = parseDefinitionsSources(cacheDefs, parserContext);
builder.addPropertyValue("cacheOperationSources", attributeSourceDefinitions);
}
else {
// 没有 caching 元素,用 "org.springframework.cache.annotation.AnnotationCacheOperationSource"
// 创立一个默认的 bean
builder.addPropertyValue("cacheOperationSources",
new RootBeanDefinition("org.springframework.cache.annotation.AnnotationCacheOperationSource"));
}
}
// 把 caching 元素转化成 bean
private List<RootBeanDefinition> parseDefinitionsSources(List<Element> definitions, ParserContext parserContext) {ManagedList<RootBeanDefinition> defs = new ManagedList<>(definitions.size());
// 遍历
for (Element element : definitions) {defs.add(parseDefinitionSource(element, parserContext));
}
return defs;
}
// 把 caching 元素转化成 bean
private RootBeanDefinition parseDefinitionSource(Element definition, ParserContext parserContext) {// ... 代码省略}
}
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());
}
}
mvc
命名空间的处理器内容较多,这里只解析第一个 mvc:annotation-driven
,其余的有趣味能够自行摸索
AnnotationDrivenBeanDefinitionParser
的次要性能是解析 <mvc:annotation-driven/>
元素,启用注解驱动,通过 context:component-scan
标签的配置,主动扫描 @Component,@Controller,@Service,@Repository
等注解标记的组件注册到工厂中,来解决申请
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext context) {
// 元素元信息
Object source = context.extractSource(element);
XmlReaderContext readerContext = context.getReaderContext();
// ... 代码省略
// 申请映射处理器 bean
RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
// ... 代码省略
// enable-matrix-variables 属性
if (element.hasAttribute("enable-matrix-variables")) {boolean enableMatrixVariables = Boolean.parseBoolean(element.getAttribute("enable-matrix-variables"));
handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);
}
// 配置门路映射
configurePathMatchingProperties(handlerMappingDef, element, context);
// 注册 RequestMappingHandlerMapping.class bean
readerContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME, handlerMappingDef);
// ... 代码省略
// 获取数据转换服务
RuntimeBeanReference conversionService = getConversionService(element, source, context);
// 获取验证器
RuntimeBeanReference validator = getValidator(element, source, context);
// 获取文本解析器
RuntimeBeanReference messageCodesResolver = getMessageCodesResolver(element);
// 注册 ConfigurableWebBindingInitializer.class bean
RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
// ... 代码省略
// 载入 conversionService、validator、messageCodesResolver
bindingDef.getPropertyValues().add("conversionService", conversionService);
bindingDef.getPropertyValues().add("validator", validator);
bindingDef.getPropertyValues().add("messageCodesResolver", messageCodesResolver);
// 配置音讯转换器
ManagedList<?> messageConverters = getMessageConverters(element, source, context);
// argument-resolvers 子元素配置的自定义参数解析器
ManagedList<?> argumentResolvers = getArgumentResolvers(element, context);
// return-value-handlers 子元素配置的自定义响应解析器
ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, context);
// async-support 子元素配置的异步工作超时工夫
String asyncTimeout = getAsyncTimeout(element);
// async-support 子元素配置的异步工作执行器
RuntimeBeanReference asyncExecutor = getAsyncExecutor(element);
// async-support 子元素配置的 callable-interceptors 申请拦截器
ManagedList<?> callableInterceptors = getInterceptors(element, source, context, "callable-interceptors");
// async-support 子元素配置的 deferred-result-interceptors 响应拦截器
ManagedList<?> deferredResultInterceptors = getInterceptors(element, source, context, "deferred-result-interceptors");
// 注册 RequestMappingHandlerAdapter.class bean
RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
// 载入 contentNegotiationManager、bindingDef、messageConverters
handlerAdapterDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
handlerAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
handlerAdapterDef.getPropertyValues().add("messageConverters", messageConverters);
// 载入 jackson 申请解决
addRequestBodyAdvice(handlerAdapterDef);
// 载入 jackson 响应解决
addResponseBodyAdvice(handlerAdapterDef);
// ignore-default-model-on-redirect 属性
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);
// 注册 RequestMappingHandlerAdapter.class bean
readerContext.getRegistry().registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME, handlerAdapterDef);
// 注册 CompositeUriComponentsContributorFactoryBean.class bean
RootBeanDefinition uriContributorDef =
new RootBeanDefinition(CompositeUriComponentsContributorFactoryBean.class);
uriContributorDef.setSource(source);
uriContributorDef.getPropertyValues().addPropertyValue("handlerAdapter", handlerAdapterDef);
uriContributorDef.getPropertyValues().addPropertyValue("conversionService", conversionService);
// 注册 mvcUriComponentsContributor bean
String uriContributorName = MvcUriComponentsBuilder.MVC_URI_COMPONENTS_CONTRIBUTOR_BEAN_NAME;
readerContext.getRegistry().registerBeanDefinition(uriContributorName, uriContributorDef);
// 注册 ConversionServiceExposingInterceptor.class bean
RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class);
csInterceptorDef.setSource(source);
csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService);
// 注册 MappedInterceptor.class bean
RootBeanDefinition mappedInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
// ... 代码省略
// 注册 ExceptionHandlerExceptionResolver.class bean
RootBeanDefinition methodExceptionResolver = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class);
// ... 代码省略
// 注册 ResponseStatusExceptionResolver.class bean
RootBeanDefinition statusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class);
// ... 代码省略
// 注册 DefaultHandlerExceptionResolver.class bean
RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class);
// ... 代码省略
// 注册一系列 bean
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));
// ... 代码省略
context.popAndRegisterContainingComponent();
return null;
}
}
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
// 配置门路映射
private void configurePathMatchingProperties(RootBeanDefinition handlerMappingDef, Element element, ParserContext context) {
// 获取 path-matching 子元素
Element pathMatchingElement = DomUtils.getChildElementByTagName(element, "path-matching");
if (pathMatchingElement != null) {Object source = context.extractSource(element);
// suffix-pattern 属性
if (pathMatchingElement.hasAttribute("suffix-pattern")) {Boolean useSuffixPatternMatch = Boolean.valueOf(pathMatchingElement.getAttribute("suffix-pattern"));
handlerMappingDef.getPropertyValues().add("useSuffixPatternMatch", useSuffixPatternMatch);
}
// trailing-slash 属性
if (pathMatchingElement.hasAttribute("trailing-slash")) {Boolean useTrailingSlashMatch = Boolean.valueOf(pathMatchingElement.getAttribute("trailing-slash"));
handlerMappingDef.getPropertyValues().add("useTrailingSlashMatch", useTrailingSlashMatch);
}
// registered-suffixes-only 属性
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 属性
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 属性
if (pathMatchingElement.hasAttribute("path-matcher")) {pathMatcherRef = new RuntimeBeanReference(pathMatchingElement.getAttribute("path-matcher"));
}
pathMatcherRef = MvcNamespaceUtils.registerPathMatcher(pathMatcherRef, context, source);
handlerMappingDef.getPropertyValues().add("pathMatcher", pathMatcherRef);
}
}
// 获取数据转换服务
private RuntimeBeanReference getConversionService(Element element, @Nullable Object source, ParserContext context) {
RuntimeBeanReference conversionServiceRef;
// 有配置 conversion-service 属性
if (element.hasAttribute("conversion-service")) {conversionServiceRef = new RuntimeBeanReference(element.getAttribute("conversion-service"));
}
else {
// 没有就用 FormattingConversionServiceFactoryBean 创立一个默认的
RootBeanDefinition conversionDef = new RootBeanDefinition(FormattingConversionServiceFactoryBean.class);
// ... 代码省略
conversionServiceRef = new RuntimeBeanReference(conversionName);
}
return conversionServiceRef;
}
// 获取验证器
private RuntimeBeanReference getValidator(Element element, @Nullable Object source, ParserContext context) {
// 有配置 validator 属性
if (element.hasAttribute("validator")) {return new RuntimeBeanReference(element.getAttribute("validator"));
}
else if (javaxValidationPresent) {
// 没有就用 OptionalValidatorFactoryBean 创立一个默认的
RootBeanDefinition validatorDef = new RootBeanDefinition("org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean");
// ... 代码省略
return new RuntimeBeanReference(validatorName);
}
else {return null;}
}
// 获取文本解析器
private RuntimeBeanReference getMessageCodesResolver(Element element) {
// 有配置 message-codes-resolver 属性
if (element.hasAttribute("message-codes-resolver")) {return new RuntimeBeanReference(element.getAttribute("message-codes-resolver"));
}
else {return null;}
}
}
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
// 配置音讯转换器
private ManagedList<?> getMessageConverters(Element element, @Nullable Object source, ParserContext context) {
// message-converters 子元素
Element convertersElement = DomUtils.getChildElementByTagName(element, "message-converters");
// 后果集
ManagedList<Object> messageConverters = new ManagedList<>();
// 有 message-converters 子元素
if (convertersElement != null) {
// 把 bean、ref 子元素转换为 bean,退出后果集
for (Element beanElement : DomUtils.getChildElementsByTagName(convertersElement, "bean", "ref")) {Object object = context.getDelegate().parsePropertySubElement(beanElement, null);
messageConverters.add(object);
}
}
// 有 message-converters 子元素,但有 register-defaults 属性
if (convertersElement == null || Boolean.parseBoolean(convertersElement.getAttribute("register-defaults"))) {
// 增加 ByteArrayHttpMessageConverter.class bean 到后果集
// 字节数组转换器
messageConverters.add(createConverterDefinition(ByteArrayHttpMessageConverter.class, source));
// 增加 StringHttpMessageConverter.class bean 到后果集
// 字符转换器
RootBeanDefinition stringConverterDef = createConverterDefinition(StringHttpMessageConverter.class, source);
stringConverterDef.getPropertyValues().add("writeAcceptCharset", false);
messageConverters.add(stringConverterDef);
// 增加 ResourceHttpMessageConverter.class bean 到后果集
// 资源转换器
messageConverters.add(createConverterDefinition(ResourceHttpMessageConverter.class, source));
// 增加 ResourceRegionHttpMessageConverter.class bean 到后果集
// 资源区域转换器
messageConverters.add(createConverterDefinition(ResourceRegionHttpMessageConverter.class, source));
// 增加 SourceHttpMessageConverter.class bean 到后果集
// javax.xml.transform.Source 转换器
messageConverters.add(createConverterDefinition(SourceHttpMessageConverter.class, source));
// 增加 AllEncompassingFormHttpMessageConverter.class bean 到后果集
// form-data 转换器
messageConverters.add(createConverterDefinition(AllEncompassingFormHttpMessageConverter.class, source));
// ... 代码省略
if (jackson2XmlPresent) {// 增加 jackson2Xml 转换器}
// ... 代码省略
if (jackson2Present) {// 增加 jackson2 转换器}
else if (gsonPresent) {// 增加 gson 转换器}
// ... 代码省略
}
return messageConverters;
}
}
后续
更多博客,查看 https://github.com/senntyou/blogs
作者:深予之 (@senntyou)
版权申明:自在转载 - 非商用 - 非衍生 - 放弃署名(创意共享 3.0 许可证)