Spring源码中的工具类

本文深入探讨了Spring框架的关键组成部分,包括spring-core、spring-beans、spring-aop、spring-context和spring-webmvc模块的功能和作用。从标准元数据读取到AOP代理创建,再到Web MVC请求处理,全面解析了Spring框架的底层实现和技术细节。

文章目录

spring-core

整合了asm和cglib包,并定制了部分功能

StandardAnnotationMetadata 取类描述信息

根据注解生成AnnotatedGenericBeanDefinition时很有用

 StandardAnnotationMetadata.from(type);

AnnotatedElementUtils、AnnotationUtils查找类注释

Method m = Leaf.class.getMethod("annotatedOnLeaf");
assertThat(m.getAnnotation(Order.class)).isNotNull();
assertThat(AnnotationUtils.getAnnotation(m, Order.class)).isNotNull();
assertThat(AnnotationUtils.findAnnotation(m, Order.class)).isNotNull();

DefaultConversionService 默认转换器,设包含一组类型转换器

assertThat(conversionService.convert("false", Boolean.class)).isEqualTo(false);
assertThat(conversionService.convert("off", Boolean.class)).isEqualTo(false);
assertThat(conversionService.convert("no", Boolean.class)).isEqualTo(false);
assertThat(conversionService.convert("0", Boolean.class)).isEqualTo(false);
assertThat(conversionService.convert("FALSE", Boolean.class)).isEqualTo(false);
assertThat(conversionService.convert("OFF", Boolean.class)).isEqualTo(false);
assertThat(conversionService.convert("NO", Boolean.class)).isEqualTo(false);

SimpleCommandLineArgsParser 简单的解析命令行数据

final SimpleCommandLineArgsParser parser = new SimpleCommandLineArgsParser();
CommandLineArgs args = parser.parse("--o1");
assertThat(args.containsOption("o1")).isTrue();
assertThat(args.getOptionValues("o1")).isEqualTo(Collections.EMPTY_LIST);

JOptCommandLinePropertySource 扩展自CommandLinePropertySource解析命令行参数


@Test
void withRequiredArg_andMultipleArgsPresent_usingDelimiter() {
	OptionParser parser = new OptionParser();
	parser.accepts("foo").withRequiredArg().withValuesSeparatedBy(',');
	OptionSet options = parser.parse("--foo=bar,baz,biz");

	CommandLinePropertySource<?> ps = new JOptCommandLinePropertySource(options);
	assertThat(ps.getOptionValues("foo")).containsExactly("bar", "baz", "biz");
	assertThat(ps.getProperty("foo")).isEqualTo("bar,baz,biz");
}

@Test
void withRequiredArg_andMultipleArgsPresent_usingRepeatedOption() {
	OptionParser parser = new OptionParser();
	parser.accepts("foo").withRequiredArg().withValuesSeparatedBy(',');
	OptionSet options = parser.parse("--foo=bar", "--foo=baz", "--foo=biz");

	CommandLinePropertySource<?> ps = new JOptCommandLinePropertySource(options);
	assertThat(ps.getOptionValues("foo")).containsExactly("bar", "baz", "biz");
	assertThat(ps.getProperty("foo")).isEqualTo("bar,baz,biz");
}

MutablePropertySources 包含一组资源文件,可以设置顺序

MutablePropertySources sources = new MutablePropertySources();
sources.addLast(new MockPropertySource("b").withProperty("p1", "bValue"));
sources.addLast(new MockPropertySource("d").withProperty("p1", "dValue"));
sources.addLast(new MockPropertySource("f").withProperty("p1", "fValue"));

assertThat(sources.size()).isEqualTo(3);
assertThat(sources.contains("a")).isFalse();
assertThat(sources.contains("b")).isTrue();
assertThat(sources.contains("c")).isFalse();
assertThat(sources.contains("d")).isTrue();
assertThat(sources.contains("e")).isFalse();
assertThat(sources.contains("f")).isTrue();
assertThat(sources.contains("g")).isFalse();

assertThat(sources.get("b")).isNotNull();
assertThat(sources.get("b").getProperty("p1")).isEqualTo("bValue");
assertThat(sources.get("d")).isNotNull();
assertThat(sources.get("d").getProperty("p1")).isEqualTo("dValue");

sources.addBefore("b", new MockPropertySource("a"));
sources.addAfter("b", new MockPropertySource("c"));

ResourceUtils 加载资源

StylerUtils 指定toString的打印格式

SimpleMetadataReaderFactory 读取元数据,5.2新加

MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(AnnotatedComponentSubClass.class.getName());
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(AnnotatedComponent.class.getName());
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
assertThat(metadata.getClassName()).isEqualTo(AnnotatedComponent.class.getName());
assertThat(metadata.isInterface()).isFalse();
assertThat(metadata.isAnnotation()).isFalse();
assertThat(metadata.isAbstract()).isFalse();
assertThat(metadata.isConcrete()).isTrue();
assertThat(metadata.hasSuperClass()).isTrue();
assertThat(metadata.getSuperClassName()).isEqualTo(Object.class.getName());
assertThat(metadata.getInterfaceNames().length).isEqualTo(1);
assertThat(metadata.getInterfaceNames()[0]).isEqualTo(Serializable.class.getName());

assertThat(metadata.isAnnotated(Component.class.getName())).isTrue();

assertThat(metadata.isAnnotated(NamedComposedAnnotation.class.getName())).isTrue();

assertThat(metadata.hasAnnotation(Component.class.getName())).isTrue();
assertThat(metadata.hasAnnotation(Scope.class.getName())).isTrue();
assertThat(metadata.hasAnnotation(SpecialAttr.class.getName())).isTrue();
Set<MethodMetadata> methods = classMetadata.getAnnotatedMethods(TestAutowired.class.getName());
assertThat(methods).hasSize(1);
for (MethodMetadata methodMetadata : methods) {
	assertThat(methodMetadata.isAnnotated(TestAutowired.class.getName())).isTrue();
}

AnnotationTypeFilter 判断指定类是否有某个注解

MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
String classUnderTest = "example.type.AnnotationTypeFilterTestsTypes$SomeSubclassOfSomeComponent";
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(classUnderTest);

AnnotationTypeFilter filter = new AnnotationTypeFilter(InheritedAnnotation.class);
assertThat(filter.match(metadataReader, metadataReaderFactory)).isTrue();
ClassloadingAssertions.assertClassNotLoaded(classUnderTest);

AspectJTypeFilter 判断类和指定描述是否一致

String type = "example.type.AspectJTypeFilterTestsTypes$SomeClass";
String typePattern = "example.type.AspectJTypeFilterTestsTypes.SomeClassX";
MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(type);

AspectJTypeFilter filter = new AspectJTypeFilter(typePattern, getClass().getClassLoader());
assertThat(filter.match(metadataReader, metadataReaderFactory)).isFalse();
ClassloadingAssertions.assertClassNotLoaded(type);

ExceptionDepthComparator 异常深度比较器

Class<? extends Throwable> foundClass = ExceptionDepthComparator.findClosestMatch(Arrays.asList(SameDepthException.class, TargetException.class), new TargetException());
assertThat(foundClass).isEqualTo(TargetException.class);

StopWatch 秒表,监视任务性能耗时

StreamUtils FileCopyUtils FileSystemUtils 流、文件操作

InputStream inputStream = spy(new ByteArrayInputStream(bytes));
byte[] actual = StreamUtils.copyToByteArray(inputStream);

Charset charset = Charset.defaultCharset();
InputStream inputStream = spy(new ByteArrayInputStream(string.getBytes(charset)));
String actual = StreamUtils.copyToString(inputStream, charset);


ByteArrayInputStream in = new ByteArrayInputStream(content);
ByteArrayOutputStream out = new ByteArrayOutputStream(content.length);
int count = FileCopyUtils.copy(in, out);

	String content = "content";
StringReader in = new StringReader(content);
StringWriter out = new StringWriter();
int count = FileCopyUtils.copy(in, out);

String content = "content";
StringWriter out = new StringWriter();
FileCopyUtils.copy(content, out);

String content = "content";
StringReader in = new StringReader(content);
String result = FileCopyUtils.copyToString(in);


File src = new File("./tmp/src");
File child = new File(src, "child");
File grandchild = new File(child, "grandchild");

grandchild.mkdirs();

File bar = new File(child, "bar.txt");
bar.createNewFile();

assertThat(src.exists()).isTrue();
assertThat(child.exists()).isTrue();
assertThat(grandchild.exists()).isTrue();
assertThat(bar.exists()).isTrue();

File dest = new File("./dest");
FileSystemUtils.copyRecursively(src, dest);

assertThat(dest.exists()).isTrue();
assertThat(new File(dest, child.getName()).exists()).isTrue();

FileSystemUtils.deleteRecursively(src);

GenericTypeResolver 解析泛型

map = GenericTypeResolver.getTypeVariableMap(MySimpleInterfaceType.class);
assertThat(map.toString()).isEqualTo("{T=class java.lang.String}");

map = GenericTypeResolver.getTypeVariableMap(MyCollectionInterfaceType.class);
assertThat(map.toString()).isEqualTo("{T=java.util.Collection<java.lang.String>}");

spring-beans

依赖spring-core

SimpleBeanDefinitionRegistry BeanDefinitionRegistry接口的简单实现

只提供注册表功能,没有内置的工厂功能。例如,可以用于测试bean定义读取器

BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
AnnotatedBeanDefinition bd = new AnnotatedGenericBeanDefinition(ComponentWithName.class);
String beanName = this.beanNameGenerator.generateBeanName(bd, registry);
assertThat(beanName).as("The generated beanName must *never* be null.").isNotNull();
assertThat(StringUtils.hasText(beanName)).as("The generated beanName must *never* be blank.").isTrue();
assertThat(beanName).isEqualTo("walden");

BeanExpressionContext 上下文对象,用于对bean定义中的表达式求值

PropertyResourceConfigurer 实现了BeanFactoryPostProcessor,可以在Bean定义时修改值

PropertyPlaceholderConfigurer 继承PropertyResourceConfigurer,解析占位符,5.2已启用

5.2后推荐使用 PropertySourcesPlaceholderConfigurer

DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
BeanDefinitionBuilder builder = new BeanDefinitionBuilder(new GenericBeanDefinition());
builder.beanDefinition.setBeanClass(TestBean.class);
	bf.registerBeanDefinition("testBean",
			builder.addPropertyValue("name", "${my.name}")
				.getBeanDefinition());

	PropertyPlaceholderConfigurer pc = new PropertyPlaceholderConfigurer();
	Resource resource = new ClassPathResource("PropertyPlaceholderConfigurerTests.properties", this.getClass());
	pc.setLocation(resource);
	pc.postProcessBeanFactory(bf);

YamlPropertiesFactoryBean 解析yml文件

YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(new ByteArrayResource("foo: bar\nspam:\n  foo: baz".getBytes()));
Properties properties = factory.getObject();
assertThat(properties.getProperty("foo")).isEqualTo("bar");
assertThat(properties.getProperty("spam.foo")).isEqualTo("baz");

CustomEditorConfigurer 实现了BeanFactoryPostProcessor,可以自定义编辑器,改包下还有大量其他编辑器

DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
CustomEditorConfigurer cec = new CustomEditorConfigurer();
final DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, Locale.GERMAN);
cec.setPropertyEditorRegistrars(new PropertyEditorRegistrar[] {
		new PropertyEditorRegistrar() {
			@Override
			public void registerCustomEditors(PropertyEditorRegistry registry) {
				registry.registerCustomEditor(Date.class, new CustomDateEditor(df, true));
			}
		}});
cec.postProcessBeanFactory(bf);

MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("date", "2.12.1975");
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
bd1.setPropertyValues(pvs);
bf.registerBeanDefinition("tb1", bd1);
pvs = new MutablePropertyValues();
pvs.add("someMap[myKey]", new TypedStringValue("2.12.1975", Date.class));
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
bd2.setPropertyValues(pvs);
bf.registerBeanDefinition("tb2", bd2);

TestBean tb1 = (TestBean) bf.getBean("tb1");
assertThat(tb1.getDate()).isEqualTo(df.parse("2.12.1975"));
TestBean tb2 = (TestBean) bf.getBean("tb2");
assertThat(tb2.getSomeMap().get("myKey")).isEqualTo(df.parse("2.12.1975"));

PropertyEditorRegistrySupport PropertyEditorRegistry接口的基本实现。提供对默认编辑器和自定义编辑器的管理。主要用作BeanWrapperImpl的基类

@Nullable
public PropertyEditor getDefaultEditor(Class<?> requiredType) {
    if (!this.defaultEditorsActive) {
    	return null;
    }
    if (this.overriddenDefaultEditors != null) {
    	PropertyEditor editor = this.overriddenDefaultEditors.get(requiredType);
    	if (editor != null) {
    		return editor;
    	}
    }
    if (this.defaultEditors == null) {
        // 核心,懒加载所有编辑器
    	createDefaultEditors();
    }
    return this.defaultEditors.get(requiredType);
}

private void createDefaultEditors() {
    this.defaultEditors = new HashMap<>(64);
    
    // Simple editors, without parameterization capabilities.
    // The JDK does not contain a default editor for any of these target types.
    this.defaultEditors.put(Charset.class, new CharsetEditor());
    this.defaultEditors.put(Class.class, new ClassEditor());
    this.defaultEditors.put(Class[].class, new ClassArrayEditor());
    this.defaultEditors.put(Currency.class, new CurrencyEditor());
    this.defaultEditors.put(File.class, new FileEditor());
    this.defaultEditors.put(InputStream.class, new InputStreamEditor());
    this.defaultEditors.put(InputSource.class, new InputSourceEditor());
    this.defaultEditors.put(Locale.class, new LocaleEditor());
    this.defaultEditors.put(Path.class, new PathEditor());
.....
    
}

TypeConverterDelegate 类型转换为指定类型的助手类,由BeanWrapperImpl和SimpleTypeConverter调用

内部保存了 PropertyEditorRegistrySupport

BeanUtils 对象复制、实例化、方法查找、属性描述等

ArgumentConvertingMethodInvoker 通过参数调用方法,支持重载

ArgumentConvertingMethodInvoker methodInvoker = new ArgumentConvertingMethodInvoker();
methodInvoker.setTargetClass(TestClass1.class);
methodInvoker.setTargetMethod("intArgument");
methodInvoker.setArguments(5);
methodInvoker.prepare();
methodInvoker.invoke();

methodInvoker = new ArgumentConvertingMethodInvoker();
methodInvoker.setTargetClass(TestClass1.class);
methodInvoker.setTargetMethod("intArgument");
methodInvoker.setArguments(5);
methodInvoker.prepare();
methodInvoker.invoke();

PagedListHolder 将对象以分页形式展示

BeanWrapperImpl 包装指定类

BeanWrapper bw = new BeanWrapperImpl(TestBean.class);
assertThat(bw.isWritableProperty("name")).isTrue();
assertThat(bw.isWritableProperty("age")).isTrue();

CachedIntrospectionResults 缓存PropertyDescriptor,不建议应用程序使用

BeanWrapper bw = new BeanWrapperImpl(TestBean.class);
assertThat(bw.isWritableProperty("name")).isTrue();
assertThat(bw.isWritableProperty("age")).isTrue();
assertThat(CachedIntrospectionResults.strongClassCache.containsKey(TestBean.class)).isTrue();

ClassLoader child = new OverridingClassLoader(getClass().getClassLoader());
Class<?> tbClass = child.loadClass("org.springframework.beans.testfixture.beans.TestBean");
assertThat(CachedIntrospectionResults.strongClassCache.containsKey(tbClass)).isFalse();
CachedIntrospectionResults.acceptClassLoader(child);
bw = new BeanWrapperImpl(tbClass);
assertThat(bw.isWritableProperty("name")).isTrue();
assertThat(bw.isWritableProperty("age")).isTrue();
assertThat(CachedIntrospectionResults.strongClassCache.containsKey(tbClass)).isTrue();
CachedIntrospectionResults.clearClassLoader(child);
assertThat(CachedIntrospectionResults.strongClassCache.containsKey(tbClass)).isFalse();

assertThat(CachedIntrospectionResults.strongClassCache.containsKey(TestBean.class)).isTrue();

ExtendedBeanInfoFactory、ExtendedBeanInfo 解决链式调用问题

MutablePropertyValues PropertyValues的简单实现

TestBean target = new TestBean();
String newName = "tony";
String invalidTouchy = ".valid";
BeanWrapper accessor = createAccessor(target);
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.addPropertyValue(new PropertyValue("age", "foobar"));
pvs.addPropertyValue(new PropertyValue("name", newName));
pvs.addPropertyValue(new PropertyValue("touchy", invalidTouchy));
assertThatExceptionOfType(PropertyBatchUpdateException.class).isThrownBy(() ->
		accessor.setPropertyValues(pvs))
	.satisfies(ex -> {
		assertThat(ex.getExceptionCount()).isEqualTo(2);
		assertThat(ex.getPropertyAccessException("touchy").getPropertyChangeEvent()
				.getNewValue()).isEqualTo(invalidTouchy);
	});
// Test validly set property matches
assertThat(target.getName().equals(newName)).as("Valid set property must stick").isTrue();
assertThat(target.getAge() == 0).as("Invalid set property must retain old value").isTrue();

BeanDefinitionBuilder 构建BeanDefinition

BeanDefinitionBuilder bdb = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class);
bdb.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bdb.addPropertyValue("age", "15");
for (String dependsOnEntry : dependsOn) {
	bdb.addDependsOn(dependsOnEntry);
}

RootBeanDefinition rbd = (RootBeanDefinition) bdb.getBeanDefinition();

BeanDefinitionReaderUtils 注册bean

BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, beanName);
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);


PropertyAccessorUtils bean属性访问

spring-aop

依赖spring-core、spring-beans

AnnotationAwareAspectJAutoProxyCreator @Aspect动态创建代理

AopProxyUtils

completeProxiedInterfaces(AdvisedSupport advised)

为代理对象添加标记接口

boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class);
boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class);
boolean addDecoratingProxy = (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class));

spring-context

ConfigurationClassPostProcessor 扫描注解,进行注册bean

ConfigurationClassParser 解析@Configuration的注解类

ConfigurationClassEnhancer 代理增强@Configuration修饰的类,实现对@Bean发现的拦截

PostProcessorRegistrationDelegate AbstractApplicationContext的后处理器处理的委托。

StandardBeanExpressionResolver spEl表达式解析

ResourceEditorRegistrar 添加资源编码器,对URL\File等资源解析

AnnotationMetadata.introspect(class) 自省方式获取bean

AnnotationConfigUtils.attributesFor(metadata, Bean.class) 获取bean注释信息

AnnotationConfigUtils 配置了大量和注释相关的上下信息,AnnotationConfigApplicationContext回去使用

spring-webmvc

RequestMappingHandlerAdapter

afterPropertiesSet 初始mvc常用的参数解析器,初始参数解析器和返回参数解析器

private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
		List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();

		// Annotation-based argument resolution
		resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
		resolvers.add(new RequestParamMapMethodArgumentResolver());
		resolvers.add(new PathVariableMethodArgumentResolver());
		resolvers.add(new PathVariableMapMethodArgumentResolver());
		resolvers.add(new MatrixVariableMethodArgumentResolver());
		resolvers.add(new MatrixVariableMapMethodArgumentResolver());
		resolvers.add(new ServletModelAttributeMethodProcessor(false));
		resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
		resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
		resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
		resolvers.add(new RequestHeaderMapMethodArgumentResolver());
		resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
		resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
		resolvers.add(new SessionAttributeMethodArgumentResolver());
		resolvers.add(new RequestAttributeMethodArgumentResolver());

		// Type-based argument resolution
		resolvers.add(new ServletRequestMethodArgumentResolver());
		resolvers.add(new ServletResponseMethodArgumentResolver());
		resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
		resolvers.add(new RedirectAttributesMethodArgumentResolver());
		resolvers.add(new ModelMethodProcessor());
		resolvers.add(new MapMethodProcessor());
		resolvers.add(new ErrorsMethodArgumentResolver());
		resolvers.add(new SessionStatusMethodArgumentResolver());
		resolvers.add(new UriComponentsBuilderMethodArgumentResolver());

		// Custom arguments
		if (getCustomArgumentResolvers() != null) {
			resolvers.addAll(getCustomArgumentResolvers());
		}

		// Catch-all
		resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
		resolvers.add(new ServletModelAttributeMethodProcessor(true));

		return resolvers;
	}

	/**
	 * Return the list of argument resolvers to use for {@code @InitBinder}
	 * methods including built-in and custom resolvers.
	 */
	private List<HandlerMethodArgumentResolver> getDefaultInitBinderArgumentResolvers() {
		List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();

		// Annotation-based argument resolution
		resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
		resolvers.add(new RequestParamMapMethodArgumentResolver());
		resolvers.add(new PathVariableMethodArgumentResolver());
		resolvers.add(new PathVariableMapMethodArgumentResolver());
		resolvers.add(new MatrixVariableMethodArgumentResolver());
		resolvers.add(new MatrixVariableMapMethodArgumentResolver());
		resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
		resolvers.add(new SessionAttributeMethodArgumentResolver());
		resolvers.add(new RequestAttributeMethodArgumentResolver());

		// Type-based argument resolution
		resolvers.add(new ServletRequestMethodArgumentResolver());
		resolvers.add(new ServletResponseMethodArgumentResolver());

		// Custom arguments
		if (getCustomArgumentResolvers() != null) {
			resolvers.addAll(getCustomArgumentResolvers());
		}

		// Catch-all
		resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));

		return resolvers;
	}

	/**
	 * Return the list of return value handlers to use including built-in and
	 * custom handlers provided via {@link #setReturnValueHandlers}.
	 */
	private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
		List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();

		// Single-purpose return value types
		handlers.add(new ModelAndViewMethodReturnValueHandler());
		handlers.add(new ModelMethodProcessor());
		handlers.add(new ViewMethodReturnValueHandler());
		handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(),
				this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));
		handlers.add(new StreamingResponseBodyReturnValueHandler());
		handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
				this.contentNegotiationManager, this.requestResponseBodyAdvice));
		handlers.add(new HttpHeadersReturnValueHandler());
		handlers.add(new CallableMethodReturnValueHandler());
		handlers.add(new DeferredResultMethodReturnValueHandler());
		handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));

		// Annotation-based return value types
		handlers.add(new ModelAttributeMethodProcessor(false));
		handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
				this.contentNegotiationManager, this.requestResponseBodyAdvice));

		// Multi-purpose return value types
		handlers.add(new ViewNameMethodReturnValueHandler());
		handlers.add(new MapMethodProcessor());

		// Custom return value types
		if (getCustomReturnValueHandlers() != null) {
			handlers.addAll(getCustomReturnValueHandlers());
		}

		// Catch-all
		if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
			handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
		}
		else {
			handlers.add(new ModelAttributeMethodProcessor(true));
		}

		return handlers;
	}
	```
## RequestMappingHandlerMapping 
afterPropertiesSet -> initHandlerMethods 负责注册handelMappering

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值