定义: 根据HandlerMethod信息,对http请求进行参数解析,并完成调用java
先看一下HandlerAdapter的接口定义web
public interface HandlerAdapter {
//判断是否支持该handler类型的解析
boolean supports(Object handler);
//参数解析 并调用handler完成过程调用
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
//用于处理http请求头中的last-modified
long getLastModified(HttpServletRequest request, Object handler);
}
复制代码
以RequestMappingHandlerAdapter为例来说,先看下继承关系spring
同RequestMappingHandlerMapping都有ApplicationContextAware,ServletContextAware,InitializingBean三个生命周期方法json
这里咱们就直接看InitializingBean了浏览器
#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
@Override
public void afterPropertiesSet() {
// 1.装载@ControllerAdvice注解的类
initControllerAdviceCache();
// 2.装载ArgumentResolver(默认+自定义)
if (this.argumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
//包装成一个Composite对象
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
// 2.装载InitBinderArgumentResolvers(默认+自定义)
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
//包装成一个Composite对象
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
// 3.装载ReturnValueHandlers(默认+自定义)
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
//包装成一个Composite对象
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
复制代码
过程归纳:缓存
装载带有ControllerAdvices注解的对象bash
private void initControllerAdviceCache() {
//从容器中获取全部带有ControllerAdvices注解的类名 并包装成ControllerAdviceBean
List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
OrderComparator.sort(beans);
List<Object> responseBodyAdviceBeans = new ArrayList<Object>();
for (ControllerAdviceBean bean : beans) {
//筛选出带有@ModelAttribute且不带@RequestMapping注解的方法
Set<Method> attrMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS);
if (!attrMethods.isEmpty()) {
//保存到modelAttributeAdviceCache中
this.modelAttributeAdviceCache.put(bean, attrMethods);
}
//筛选出带InitBinder注解的方法 添加到initBinderAdviceCache中
Set<Method> binderMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS);
if (!binderMethods.isEmpty()) {
this.initBinderAdviceCache.put(bean, binderMethods);
}
//筛选实现RequestBodyAdvice接口 添加到requestResponseBodyAdviceBeans中
if (RequestBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
requestResponseBodyAdviceBeans.add(bean);
if (logger.isInfoEnabled()) {
logger.info("Detected RequestBodyAdvice bean in " + bean);
}
}
//筛选实现ResponseBodyAdvice接口 添加到requestResponseBodyAdviceBeans中
if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
requestResponseBodyAdviceBeans.add(bean);
if (logger.isInfoEnabled()) {
logger.info("Detected ResponseBodyAdvice bean in " + bean);
}
}
}
//保存到全局变量
if (!responseBodyAdviceBeans.isEmpty()) {
this.responseBodyAdvice.addAll(0, responseBodyAdviceBeans);
}
}
复制代码
装载ArgumentResolvers(默认+自定义)session
装载InitBinderArgumentResolvers(默认+自定义)mvc
装载ReturnValueHandlers(默认+自定义)app
自定义拓展方式放后面说
如下为HandlerAdapter默认解析器
//参数解析器
public interface HandlerMethodArgumentResolver {
//判断是否支持该参数的解析(根据类型,注解等)
boolean supportsParameter(MethodParameter parameter);
//对参数进行解析 获得解析结果
Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;
}
//返回值解析器
public interface HandlerMethodReturnValueHandler {
//判断是否支持该返回值的解析(根据类型,注解等)
boolean supportsReturnType(MethodParameter returnType);
//对返回值进行解析
void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}
复制代码
//1.调用support()方法判断是否支持HandlerMethod的解析
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 若是是Get或Head请求 调用getLastModified()获取上次更新时间
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
//若是小于浏览器缓存更新时间 则直接返回 浏览器使用本地缓存
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
复制代码
过程总结:
调用support()方法判断是否支持改handler的解析
#org.springframework.web.servlet.DispatcherServlet
//在doDispatch()方法中调用了getHandlerAdapter(Object)方法来获得一个HandlerAdapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
//调用HandlerAdapter.support()方法 判断是否支持该handler对象的解析
for (HandlerAdapter ha : this.handlerAdapters) {
...
if (ha.supports(handler)) {
return ha;
}
}
...
}
#org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter
//根据handler对象判断是否支持handler解析
@Override
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
@Override
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
复制代码
若是是Get或Head请求 调用getLastModified()获取上次更新时间
若是小于浏览器缓存更新时间 则直接返回 浏览器使用本地缓存
#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
@Override
protected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) {
return -1;
}
复制代码
调用handler()方法完成过程调用(参数解析 返回值解析)
#org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter
@Override
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//对http协议缓存方面的请求头的处理(expire,cache-control)
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
}else {
checkAndPrepare(request, response, true);
}
//是否使用session锁
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
//获得互斥量
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {//执行过程调用
return invokeHandleMethod(request, response, handlerMethod);
}
}
}
//执行过程调用(参数解析 过程调用)
return invokeHandleMethod(request, response, handlerMethod);
}
复制代码
//根据HandlerMethod解析参数 并完成过程调用获得一个ModelAndView
private ModelAndView invokeHandleMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
//对@InitBinder的处理 主要是聚合了@InitBinder的全部处理方法
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
//@ModelAttribute的处理
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
//对HandlerMethod的装饰,主要是增长了参数解析和返回值转化的功能
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
//提供对参数解析的支持
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
//提供对返回值解析的支持
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
//提供对@InitBinder处理的支持
invocableMethod.setDataBinderFactory(binderFactory);
//TODO 尚不明功能
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
//能够看作handler()过程的上下文
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
==========================异步处理分割线=============
//AsyncWebRequest内部持有AsyncContext 能够经过其开启异步任务
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
//异步处理Manager
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
//设置异步执行线程池
asyncManager.setTaskExecutor(this.taskExecutor);
//提供对异步处理的支持
asyncManager.setAsyncWebRequest(asyncWebRequest);
//异步调用拦截器
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
//若是异步处理完成
if (asyncManager.hasConcurrentResult()) {
//获取异步执行结果
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
...
//替换invocableMethod(原先异步处理的方法返回值是Callable如今直接返回结果)
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
//对invocableMethod进行参数解析,过程调用,返回值转化
//并将结果存到mavContainer中
invocableMethod.invokeAndHandle(webRequest, mavContainer);
//若是异步处理正在执行(已经开始,还没有结束) 马上返回
//同时DispatcherServlet也直接返回 等待AsyncContext.dispatch()调用再次进入doDispatch()方法
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
//从mavContainer捞出结果
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
复制代码
以上是invokeHandleMethod()的完整过程
但在调用过程当中实际从异步处理分割线开始分为2种状况:
同步调用: 过程比较简单,直接进行参数解析和返回值转化就行了
invocableMethod.invokeAndHandle(webRequest, mavContainer);
return getModelAndView(mavContainer, modelFactory, webRequest);
复制代码
异步调用:
再分为两种状况:
异步处理中(已开始,还没有完成)
//AsyncWebRequest内部持有AsyncContext 能够经过其开启异步任务
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
//异步处理Manager
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
//设置异步执行线程池
asyncManager.setTaskExecutor(this.taskExecutor);
//提供对异步处理的支持
asyncManager.setAsyncWebRequest(asyncWebRequest);
//异步调用拦截器
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
//对invocableMethod进行参数解析,过程调用(调用AsyncWebRequest.startAsync()执行异步过程),返回值转化
//并将结果存到mavContainer中
invocableMethod.invokeAndHandle(webRequest, mavContainer);
//若是异步处理正在执行(已经开始,还没有结束) 马上返回
//同时DispatcherServlet也直接返回
return null;
#org.springframework.web.servlet.DispatcherServlet
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
...
}
//等待AsyncWebRequest.dispatch()被调用 而后再次进入doDispatch()方法
复制代码
异步执行完成,再次进入doDispatch()流程
//AsyncWebRequest内部持有AsyncContext 能够经过其开启异步任务
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
//异步处理Manager
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
//设置异步执行线程池
asyncManager.setTaskExecutor(this.taskExecutor);
//提供对异步处理的支持
asyncManager.setAsyncWebRequest(asyncWebRequest);
//异步调用拦截器
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
//异步处理完成 获取异步执行结果
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
//替换invocableMethod(原先异步处理的方法返回值是Callable如今直接返回结果)
invocableMethod = invocableMethod.wrapConcurrentResult(result);
//对invocableMethod进行参数解析,过程调用,返回值转化
//并将结果存到mavContainer中
invocableMethod.invokeAndHandle(webRequest, mavContainer);
//从mavContainer捞出结果
return getModelAndView(mavContainer, modelFactory, webRequest);
复制代码
先看一下ServletInvocableHandlerMethod是个什么东东
HandlerMethod:保存了处理过程方法
InvocableHandlerMethod: 对HandlerMethod的装饰,增长了参数解析的功能
ServletInvocableHandlerMethod:对HandlerMethod的装饰,增长了返回值转化的功能
invocableMethod.invokeAndHandle(webRequest, mavContainer);
#org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod
public void invokeAndHandle(ServletWebRequest webRequest,
ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// 1.1 参数解析 并完成过程调用
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
...
try {
//1.2 使用returnValueHandlers对返回结果进行处理 讲结果塞到mavContainer中 过程相似参数解析
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
}
#org.springframework.web.method.support.InvocableHandlerMethod
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//1.1.1 参数解析并获得绑定的结果
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
...
//1.1.2 反射完成过程调用
Object returnValue = doInvoke(args);
...
return returnValue;
}
private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//参数信息
MethodParameter[] parameters = getMethodParameters();
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
//调用HandlerMethodArgumentResolver#supportsParameter判断是否支持该参数的解析
if (this.argumentResolvers.supportsParameter(parameter)) {
try {
//调用HandlerMethodArgumentResolver#resolveArgument进行解析
args[i] = this.argumentResolvers.resolveArgument(
parameter, mavContainer, request, this.dataBinderFactory);
continue;
}
...
}
...
}
return args;
}
复制代码
包装ModelAndView getModelAndView(mavContainer, modelFactory, webRequest);
//从mavContainer取出结果 包装成ModelAndView
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
modelFactory.updateModel(webRequest, mavContainer);
if (mavContainer.isRequestHandled()) {
return null;
}
ModelMap model = mavContainer.getModel();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model);
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
//若是是redirect请求
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
return mav;
}
复制代码
到此 HandlerAdapter.handler的调用过程算分析完了
WebDataBinder:数据(对象属性)绑定器,用于对对象的属性进行转化(Formatter)和校验(Validator)
InitBinder: @InitBinder注解用于在参数解析前初始化WebDataBinder.简单来讲就是能够对WebDataBinder增长Validator和属性转化器Formatter
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface InitBinder {
//在哪些属性上发生做用
String[] value() default {};
}
复制代码
示例
@InitBinder
protected void initBinder(WebDataBinder binder) {
//添加自定义Data类型Formatter
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}
复制代码
@InitBinder方法分为两种:
全局@InitBinder:定义在注解有@ControllerAdvices的类中,装载发生在HandlerAdapter初始化调用initControllerAdviceCache()过程当中(见上文初始化过程分析)
局部@InitBinder:定义在注解有@Controller的类中,装载发生在HandlerAdapter.handler()调用getDataBinderFactory()过程当中
private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
//获取处理方法所在的类
Class<?> handlerType = handlerMethod.getBeanType();
//从保存的全局缓存中找属于该类的局部@InitBinder方法
Set<Method> methods = this.initBinderCache.get(handlerType);
if (methods == null) {//若是没找到 说明该类不是一个@ControllerAdvices注解的类(只有@Controller没有@ControllerAdvices)
//获得该类中全部@InitBinder注解的方法
methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
//将局部@InitBinder方法缓存到initBinderCache中
this.initBinderCache.put(handlerType, methods);
}
List<InvocableHandlerMethod> initBinderMethods = new ArrayList<InvocableHandlerMethod>();
//将全局@InitBinder方法包装成InvocableHandlerMethod,添加到initBinderMethods
for (Entry<ControllerAdviceBean, Set<Method>> entry : this.initBinderAdviceCache.entrySet()) {
if (entry.getKey().isApplicableToBeanType(handlerType)) {
Object bean = entry.getKey().resolveBean();
for (Method method : entry.getValue()) {
initBinderMethods.add(createInitBinderMethod(bean, method));
}
}
}
//将局部@InitBinder方法包装成InvocableHandlerMethod,添加到initBinderMethods
for (Method method : methods) {
Object bean = handlerMethod.getBean();
initBinderMethods.add(createInitBinderMethod(bean, method));
}
//使用initBinderMethods对象(局部+全局),包装成WebDataBinderFactory对象
return createDataBinderFactory(initBinderMethods);
}
protected InitBinderDataBinderFactory createDataBinderFactory(List<InvocableHandlerMethod> binderMethods) throws Exception {
return new ServletRequestDataBinderFactory(binderMethods, getWebBindingInitializer());
}
复制代码
看完了了@InitBinder的装载过程,来看下@InitBinder方法是怎样被处理的
this.argumentResolvers.resolveArgument(
parameter, mavContainer, request, this.dataBinderFactory);
复制代码
能够看到在使用argumentResolvers.resolveArgument()进行参数解析时将dataBinderFactory做为参数传递了过去
分别来看RequestParamMapMethodArgumentResolver,RequestResponseBodyMethodProcessor,ModelAttributeMethodProcessor三个参数解析器是如何处理@InitBinder方法的
RequestParamMapMethodArgumentResolver
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
// 彻底没使用binderFactory
...
}
}
复制代码
由于说过@InitBinder是用来初始化WebDataBinder的,而RequestParamMapMethodArgumentResolver是处理表单属性的(不是对象),因此彻底没用
RequestResponseBodyMethodProcessor
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
parameter = parameter.nestedIfOptional();
//使用binderFactory建立对象解析器
WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
if (arg != null) {
//使用对象解析进行参数校验
validateIfApplicable(binder, parameter);
//若是参数校验异常,且目标方法参数列表中没有BindingResult类型参数,则直接抛出参数解析异常
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
}
}
//将参数解析结果存到mavContainer上下文中
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
return adaptArgumentIfNecessary(arg, parameter);
}
复制代码
由于RequestResponseBodyMethodProcessor将属性绑定委托给了json解析器,因此这里WebDataBinder只负责参数校验
ModelAttributeMethodProcessor
@Override
public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
String name = ModelFactory.getNameForParameter(parameter);
Object attribute = (mavContainer.containsAttribute(name) ? mavContainer.getModel().get(name) :
createAttribute(name, parameter, binderFactory, webRequest));
...
WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
if (binder.getTarget() != null) {
//使用binder进行属性绑定
if (!mavContainer.isBindingDisabled(name)) {
bindRequestParameters(binder, webRequest);
}
//使用binder进行属性校验
validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new BindException(binder.getBindingResult());
}
}
// Add resolved attribute and BindingResult at the end of the model
Map<String, Object> bindingResultModel = binder.getBindingResult().getModel();
mavContainer.removeAttributes(bindingResultModel);
mavContainer.addAllAttributes(bindingResultModel);
return binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
}
protected Object createAttribute(String attributeName, MethodParameter methodParam, WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception {
return BeanUtils.instantiateClass(methodParam.getParameterType());
}
protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) {
((WebRequestDataBinder) binder).bind(request);
}
复制代码
使用WebDataBinder进行了属性绑定和属性校验