springMVC 解析过程
首先要知道web项目启动完毕,spring容器会初始化完毕,针对一些单例controller已经创建好了。已经对这个类的BeanDefinition 对象
也已经创建完成,不知道BeanDefinition 的可以看
springMVC本质就是一个servlet
springMVC 处理请求的大致过程:
核心Servlet: DispatcherServlet
核心方法: doDispatch
第一步:根据URL解析出映射字符串str与@@RequestMapping("/index.action") 这里面的字符进行匹配,不成功则报404
第二部:根据str 获得 HandlerMethod对象
第三步: 将HandlerMethod对象 重新封装一个新的HandlerMethod对象 并加入controller对象
第四部: 根据HandlerMethod对象 获得 适配器 HandlerAdapter
第五步: 适配器开始调用 handle 方法
第六步: 根据controller中的方法参数名字,获得请求对应信息
第七步: 根据controller中的方法参数的类型,将获得的信息数据 进行类型转换并将转后的数据返回
第八部: 开始利用第七部返回的参数开始反射调用我们的controller中的方法 此时线程就已经到我们自己写的controller方法了。
以上是大致过程:下面是我自己画的uml 图,看图时根据上面写的过程去看, 你会受益匪浅的。
下面是我copy的关键代码。也可以 参考。
@Override
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest webRequest) throws Exception {
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
MultipartHttpServletRequest multipartRequest =
WebUtils.getNativeRequest(servletRequest, MultipartHttpServletRequest.class);
Object arg;
if (MultipartFile.class == parameter.getParameterType()) {
assertIsMultipartRequest(servletRequest);
Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?");
arg = multipartRequest.getFile(name);
}
else if (isMultipartFileCollection(parameter)) {
assertIsMultipartRequest(servletRequest);
Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?");
arg = multipartRequest.getFiles(name);
}
else if (isMultipartFileArray(parameter)) {
assertIsMultipartRequest(servletRequest);
Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?");
List<MultipartFile> multipartFiles = multipartRequest.getFiles(name);
arg = multipartFiles.toArray(new MultipartFile[multipartFiles.size()]);
}
else if ("javax.servlet.http.Part".equals(parameter.getParameterType().getName())) {
assertIsMultipartRequest(servletRequest);
arg = servletRequest.getPart(name);
}
else if (isPartCollection(parameter)) {
assertIsMultipartRequest(servletRequest);
arg = new ArrayList<Object>(servletRequest.getParts());
}
else if (isPartArray(parameter)) {
assertIsMultipartRequest(servletRequest);
arg = RequestPartResolver.resolvePart(servletRequest);
}
else {
arg = null;
if (multipartRequest != null) {
List<MultipartFile> files = multipartRequest.getFiles(name);
if (!files.isEmpty()) {
arg = (files.size() == 1 ? files.get(0) : files);
}
}
if (arg == null) {
String[] paramValues = webRequest.getParameterValues(name);
if (paramValues != null) {
arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
}
}
}
return arg;
}
binder.setConversionService(this.conversionService);设置类型转换器,帮助前台数据与方法参数的类型转换(这里都是springmvc的默认转换器)
conversionService:封装了大量的类型转换器
ConversionService converters =
@org.springframework.format.annotation.DateTimeFormat java.lang.Long -> java.lang.String: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@c2edc29,@org.springframework.format.annotation.NumberFormat java.lang.Long -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
@org.springframework.format.annotation.DateTimeFormat java.util.Calendar -> java.lang.String: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@c2edc29
@org.springframework.format.annotation.DateTimeFormat java.util.Date -> java.lang.String: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@c2edc29
@org.springframework.format.annotation.NumberFormat java.lang.Byte -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
@org.springframework.format.annotation.NumberFormat java.lang.Double -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
@org.springframework.format.annotation.NumberFormat java.lang.Float -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
@org.springframework.format.annotation.NumberFormat java.lang.Integer -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
@org.springframework.format.annotation.NumberFormat java.lang.Short -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
@org.springframework.format.annotation.NumberFormat java.math.BigDecimal -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
@org.springframework.format.annotation.NumberFormat java.math.BigInteger -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
java.lang.Boolean -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@674cc3f2
java.lang.Character -> java.lang.Number : org.springframework.core.convert.support.CharacterToNumberFactory@2345f554
java.lang.Character -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@b0ff5e1
java.lang.Enum -> java.lang.String : org.springframework.core.convert.support.EnumToStringConverter@1d8bc739
java.lang.Long -> java.util.Calendar : org.springframework.format.datetime.DateFormatterRegistrar$LongToCalendarConverter@13b7d136
java.lang.Long -> java.util.Date : org.springframework.format.datetime.DateFormatterRegistrar$LongToDateConverter@3d83bc2f
java.lang.Number -> java.lang.Character : org.springframework.core.convert.support.NumberToCharacterConverter@44d78c73
java.lang.Number -> java.lang.Number : org.springframework.core.convert.support.NumberToNumberConverterFactory@3682db4
java.lang.Number -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@445887e8
java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.lang.Long: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@c2edc29,java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Long: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.util.Calendar: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@c2edc29
java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.util.Date: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@c2edc29
java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Byte: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Double: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Float: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Integer: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Short: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
java.lang.String -> @org.springframework.format.annotation.NumberFormat java.math.BigDecimal: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
java.lang.String -> @org.springframework.format.annotation.NumberFormat java.math.BigInteger: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
java.lang.String -> java.lang.Boolean : org.springframework.core.convert.support.StringToBooleanConverter@45ed6fe3
java.lang.String -> java.lang.Character : org.springframework.core.convert.support.StringToCharacterConverter@1042b366
java.lang.String -> java.lang.Enum : org.springframework.core.convert.support.StringToEnumConverterFactory@60d479d9
java.lang.String -> java.lang.Number : org.springframework.core.convert.support.StringToNumberConverterFactory@2c90862b
java.lang.String -> java.nio.charset.Charset : org.springframework.core.convert.support.StringToCharsetConverter@55686678
java.lang.String -> java.util.Currency : org.springframework.core.convert.support.StringToCurrencyConverter@420ba5a6
java.lang.String -> java.util.Locale : org.springframework.core.convert.support.StringToLocaleConverter@43c47e56
java.lang.String -> java.util.Properties : org.springframework.core.convert.support.StringToPropertiesConverter@31f28bdd
java.lang.String -> java.util.UUID : org.springframework.core.convert.support.StringToUUIDConverter@3a55a70a
java.nio.charset.Charset -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@391f7c16
java.util.Calendar -> java.lang.Long : org.springframework.format.datetime.DateFormatterRegistrar$CalendarToLongConverter@2a9581e8
java.util.Calendar -> java.util.Date : org.springframework.format.datetime.DateFormatterRegistrar$CalendarToDateConverter@1a27cb52
java.util.Currency -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@aa8572a
java.util.Date -> java.lang.Long : org.springframework.format.datetime.DateFormatterRegistrar$DateToLongConverter@58780dfe
java.util.Date -> java.util.Calendar : org.springframework.format.datetime.DateFormatterRegistrar$DateToCalendarConverter@31decc12
java.util.Locale -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@194262dc
java.util.Properties -> java.lang.String : org.springframework.core.convert.support.PropertiesToStringConverter@2abc73c9
java.util.UUID -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@4d499f71
org.springframework.core.convert.support.ArrayToArrayConverter@eb531fe
org.springframework.core.convert.support.ArrayToCollectionConverter@1c82db5b
org.springframework.core.convert.support.ArrayToObjectConverter@1033edfe
org.springframework.core.convert.support.ArrayToStringConverter@3cdd08b6
org.springframework.core.convert.support.ByteBufferConverter@40bc74a0
org.springframework.core.convert.support.ByteBufferConverter@40bc74a0
org.springframework.core.convert.support.ByteBufferConverter@40bc74a0
org.springframework.core.convert.support.ByteBufferConverter@40bc74a0
org.springframework.core.convert.support.CollectionToArrayConverter@530f41fc
org.springframework.core.convert.support.CollectionToCollectionConverter@19e5223d
org.springframework.core.convert.support.CollectionToObjectConverter@6fb1667b
org.springframework.core.convert.support.CollectionToStringConverter@59443425
org.springframework.core.convert.support.FallbackObjectToStringConverter@d6497f2
org.springframework.core.convert.support.IdToEntityConverter@148cd594,org.springframework.core.convert.support.ObjectToObjectConverter@2a19f216
org.springframework.core.convert.support.MapToMapConverter@122ae013
org.springframework.core.convert.support.ObjectToArrayConverter@414dc701
org.springframework.core.convert.support.ObjectToCollectionConverter@67bf4e86
org.springframework.core.convert.support.StringToArrayConverter@536703f1
org.springframework.core.convert.support.StringToCollectionConverter@cbb96ec
//TypeConverterDelegate 类中: 真是转换类型的逻辑。
public <T> T convertIfNecessary(String propertyName, Object oldValue, Object newValue,
Class<T> requiredType, TypeDescriptor typeDescriptor) throws IllegalArgumentException {
// Custom editor for this type?
PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);
ConversionFailedException conversionAttemptEx = null;
// No custom editor but custom ConversionService specified?
ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
if (editor == null && conversionService != null && newValue != null && typeDescriptor != null) {
TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
try {
return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
}
catch (ConversionFailedException ex) {
// fallback to default conversion logic below
conversionAttemptEx = ex;
}
}
}
Object convertedValue = newValue;
// Value not of required type?
if (editor != null || (requiredType != null && !ClassUtils.isAssignableValue(requiredType, convertedValue))) {
if (requiredType != null && Collection.class.isAssignableFrom(requiredType) && convertedValue instanceof String) {
TypeDescriptor elementType = typeDescriptor.getElementTypeDescriptor();
if (elementType != null && Enum.class.isAssignableFrom(elementType.getType())) {
convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
}
}
if (editor == null) {
editor = findDefaultEditor(requiredType);
}
convertedValue = doConvertValue(oldValue, convertedValue, requiredType, editor);
}
boolean standardConversion = false;
if (requiredType != null) {
// Try to apply some standard type conversion rules if appropriate.
if (convertedValue != null) {
if (Object.class == requiredType) {
return (T) convertedValue;
}
else if (requiredType.isArray()) {
// Array required -> apply appropriate conversion of elements.
if (convertedValue instanceof String && Enum.class.isAssignableFrom(requiredType.getComponentType())) {
convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
}
return (T) convertToTypedArray(convertedValue, propertyName, requiredType.getComponentType());
}
else if (convertedValue instanceof Collection) {
// Convert elements to target type, if determined.
convertedValue = convertToTypedCollection(
(Collection<?>) convertedValue, propertyName, requiredType, typeDescriptor);
standardConversion = true;
}
else if (convertedValue instanceof Map) {
// Convert keys and values to respective target type, if determined.
convertedValue = convertToTypedMap(
(Map<?, ?>) convertedValue, propertyName, requiredType, typeDescriptor);
standardConversion = true;
}
if (convertedValue.getClass().isArray() && Array.getLength(convertedValue) == 1) {
convertedValue = Array.get(convertedValue, 0);
standardConversion = true;
}
if (String.class == requiredType && ClassUtils.isPrimitiveOrWrapper(convertedValue.getClass())) {
// We can stringify any primitive value...
return (T) convertedValue.toString();
}
else if (convertedValue instanceof String && !requiredType.isInstance(convertedValue)) {
if (conversionAttemptEx == null && !requiredType.isInterface() && !requiredType.isEnum()) {
try {
Constructor<T> strCtor = requiredType.getConstructor(String.class);
return BeanUtils.instantiateClass(strCtor, convertedValue);
}
catch (NoSuchMethodException ex) {
// proceed with field lookup
if (logger.isTraceEnabled()) {
logger.trace("No String constructor found on type [" + requiredType.getName() + "]", ex);
}
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Construction via String failed for type [" + requiredType.getName() + "]", ex);
}
}
}
String trimmedValue = ((String) convertedValue).trim();
if (requiredType.isEnum() && "".equals(trimmedValue)) {
// It's an empty enum identifier: reset the enum value to null.
return null;
}
convertedValue = attemptToConvertStringToEnum(requiredType, trimmedValue, convertedValue);
standardConversion = true;
}
else if (convertedValue instanceof Number && Number.class.isAssignableFrom(requiredType)) {
convertedValue = NumberUtils.convertNumberToTargetClass(
(Number) convertedValue, (Class<Number>) requiredType);
standardConversion = true;
}
}
else {
// convertedValue == null
if (javaUtilOptionalEmpty != null && requiredType.equals(javaUtilOptionalEmpty.getClass())) {
convertedValue = javaUtilOptionalEmpty;
}
}
if (!ClassUtils.isAssignableValue(requiredType, convertedValue)) {
if (conversionAttemptEx != null) {
// Original exception from former ConversionService call above...
throw conversionAttemptEx;
}
else if (conversionService != null) {
// ConversionService not tried before, probably custom editor found
// but editor couldn't produce the required type...
TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
}
}
// Definitely doesn't match: throw IllegalArgumentException/IllegalStateException
StringBuilder msg = new StringBuilder();
msg.append("Cannot convert value of type [").append(ClassUtils.getDescriptiveType(newValue));
msg.append("] to required type [").append(ClassUtils.getQualifiedName(requiredType)).append("]");
if (propertyName != null) {
msg.append(" for property '").append(propertyName).append("'");
}
if (editor != null) {
msg.append(": PropertyEditor [").append(editor.getClass().getName()).append(
"] returned inappropriate value of type [").append(
ClassUtils.getDescriptiveType(convertedValue)).append("]");
throw new IllegalArgumentException(msg.toString());
}
else {
msg.append(": no matching editors or conversion strategy found");
throw new IllegalStateException(msg.toString());
}
}
}
if (conversionAttemptEx != null) {
if (editor == null && !standardConversion && requiredType != null && Object.class != requiredType) {
throw conversionAttemptEx;
}
logger.debug("Original ConversionService attempt failed - ignored since " +
"PropertyEditor based conversion eventually succeeded", conversionAttemptEx);
}
return (T) convertedValue;
}
看看源码,做开发的时候才能游刃有余。也能学到很多知识。springmvc的渲染过程,下次再与大家分享。