我是靠谱客的博主 呆萌钻石,最近开发中收集的这篇文章主要介绍Spring MVC 第二篇 - 关于后端处理器 HandlerMethod,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

目录

前言

HandlerMethod

ServletInvocableHandlerMethod

InvocableHandlerMethod

总结


前言

        通过前一篇文章,我们知道了 Spring MVC 执行 Controller 方法的大致流程,其中重要的一步就是找到合适的后端处理器handler),通过 handler 来执行目标方法,而我们常用的 @RequestMapping 标注的方法会对应的 handler 类型为 HandlerMethod,本文就来探究 HandlerMethod 到底是什么东西。

HandlerMethod

public class HandlerMethod {
/** Logger that is available to subclasses. */
protected final Log logger = LogFactory.getLog(getClass());
// 对应标注了 @Controller 的那个 bean,可以是对象实例也可以是一个 bean 名称
private final Object bean;
// bean 容器
@Nullable
private final BeanFactory beanFactory;
// bean 的类型
private final Class<?> beanType;
// 目标方法
private final Method method;
// 被桥接的方法,不过一般都跟 method 这个字段的值一样,目的也就是为了找到要执行的目标方法
private final Method bridgedMethod;
// 封装的参数信息
private final MethodParameter[] parameters;
// 响应码状态
@Nullable
private HttpStatus responseStatus;
// 响应码对应的原因
@Nullable
private String responseStatusReason;
// 通过下面 createWithResolvedBean 获取 HandlerMethod 的时候,会把 this 对象传递来
@Nullable
private HandlerMethod resolvedFromHandlerMethod;
// 构造函数,给上述几个字段赋值
public HandlerMethod(Object bean, Method method) {
Assert.notNull(bean, "Bean is required");
Assert.notNull(method, "Method is required");
this.bean = bean;
this.beanFactory = null;
this.beanType = ClassUtils.getUserClass(bean);
this.method = method;
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
this.parameters = initMethodParameters();
evaluateResponseStatus();
this.description = initDescription(this.beanType, this.method);
}
// 构造方法
public HandlerMethod(Object bean, String methodName, Class<?>... parameterTypes) throws NoSuchMethodException {
... 省略
}
// 构造方法
public HandlerMethod(String beanName, BeanFactory beanFactory, Method method) {
... 省略
}
// 通过 handlerMethod 复制出来一个新的 HandlerMothod, 在上篇文章中通过 HandlerMothod 类型的 Handler 来创建一个新的 ServletInvocableHandlerMethod 类型的时候,就是通过调用这个构造方法
protected HandlerMethod(HandlerMethod handlerMethod) {
Assert.notNull(handlerMethod, "HandlerMethod is required");
this.bean = handlerMethod.bean;
this.beanFactory = handlerMethod.beanFactory;
this.beanType = handlerMethod.beanType;
this.method = handlerMethod.method;
this.bridgedMethod = handlerMethod.bridgedMethod;
this.parameters = handlerMethod.parameters;
this.responseStatus = handlerMethod.responseStatus;
this.responseStatusReason = handlerMethod.responseStatusReason;
this.description = handlerMethod.description;
this.resolvedFromHandlerMethod = handlerMethod.resolvedFromHandlerMethod;
}
// 构造方法
private HandlerMethod(HandlerMethod handlerMethod, Object handler) {
... 省略
}
// 针对方法的参数来生成参数的包装类
private MethodParameter[] initMethodParameters() {
int count = this.bridgedMethod.getParameterCount();
MethodParameter[] result = new MethodParameter[count];
for (int i = 0; i < count; i++) {
result[i] = new HandlerMethodParameter(i);
}
return result;
}
// 如果方法上标注了 @ResponseStatus, 会返回该注解中的响应码和响应原因
private void evaluateResponseStatus() {
ResponseStatus annotation = getMethodAnnotation(ResponseStatus.class);
if (annotation == null) {
annotation = AnnotatedElementUtils.findMergedAnnotation(getBeanType(), ResponseStatus.class);
}
if (annotation != null) {
this.responseStatus = annotation.code();
this.responseStatusReason = annotation.reason();
}
}
//...省略一些 get 方法
// 判断该方法的返回值是否是 void
public boolean isVoid() {
return Void.TYPE.equals(getReturnType().getParameterType());
}
// 获取方法上的注解
@Nullable
public <A extends Annotation> A getMethodAnnotation(Class<A> annotationType) {
return AnnotatedElementUtils.findMergedAnnotation(this.method, annotationType);
}
public <A extends Annotation> boolean hasMethodAnnotation(Class<A> annotationType) {
return AnnotatedElementUtils.hasAnnotation(this.method, annotationType);
}
// 通过 bean 来创建 HandlerMethod,如果此时bean还没有被创建出来,会调用 getBean 方法先创建 bean 实例,此外还会将 this 对象赋值给 resolvedFromHandlerMethod
public HandlerMethod createWithResolvedBean() {
Object handler = this.bean;
if (this.bean instanceof String) {
Assert.state(this.beanFactory != null, "Cannot resolve bean name without BeanFactory");
String beanName = (String) this.bean;
handler = this.beanFactory.getBean(beanName);
}
return new HandlerMethod(this, handler);
}
// 类似 toString 方法
public String getShortLogMessage() {
return getBeanType().getName() + "#" + this.method.getName() +
"[" + this.method.getParameterCount() + " args]";
}
// 返回值的类型
private class ReturnValueMethodParameter extends HandlerMethodParameter {
@Nullable
private final Object returnValue;
public ReturnValueMethodParameter(@Nullable Object returnValue) {
super(-1);
this.returnValue = returnValue;
}
protected ReturnValueMethodParameter(ReturnValueMethodParameter original) {
super(original);
this.returnValue = original.returnValue;
}
@Override
public Class<?> getParameterType() {
return (this.returnValue != null ? this.returnValue.getClass() : super.getParameterType());
}
@Override
public ReturnValueMethodParameter clone() {
return new ReturnValueMethodParameter(this);
}
}
}

        可以看到 HandlerMethod 保存了 bean 的信息,也就是 Controller 的信息,由此可知是哪个对象,然后 Method 保存了对应的方法信息,可以知道要调用哪个方法,所以一个 @Controller 有多少个 @RequestMapping 标注的方法,就会有多少个 HandlerMethod。可是感觉这有点像一个实体类一样,并没有什么执行方法,虽然知道了 bean 信息和方法信息,但是通过这个类并没有办法来触发方法的执行,这个时候我们可以看下前面的文章,上一篇文章中分析 Controller 方法的时候是怎么执行的呢?我们应该留意到有一步是把 HandlerMethod 类型的实例转化为了 ServletInvocableHandlerMethod 类型的实例。所以下面继续分析一下这个类型又是干嘛的。

ServletInvocableHandlerMethod

public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
// 发生异常时的回调方法
private static final Method CALLABLE_METHOD = ClassUtils.getMethod(Callable.class, "call");
// 用于处理方法的返回值
@Nullable
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
// 构造函数
public ServletInvocableHandlerMethod(Object handler, Method method) {
super(handler, method);
}
public ServletInvocableHandlerMethod(HandlerMethod handlerMethod) {
super(handlerMethod);
}
// 设置处理返回值的 HandlerMethodReturnValueHandler
public void setHandlerMethodReturnValueHandlers(HandlerMethodReturnValueHandlerComposite returnValueHandlers) {
this.returnValueHandlers = returnValueHandlers;
}
// 通过该方法来触发目标方法的执行
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 执行目标方法
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
// 设置响应状态
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
disableContentCachingIfNecessary(webRequest);
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
// 设置该标识代表请求未处理完成
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
// 处理目标方法的返回值
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}
// 设置响应状态
private void setResponseStatus(ServletWebRequest webRequest) throws IOException {
HttpStatus status = getResponseStatus();
if (status == null) {
return;
}
HttpServletResponse response = webRequest.getResponse();
if (response != null) {
String reason = getResponseStatusReason();
if (StringUtils.hasText(reason)) {
response.sendError(status.value(), reason);
}
else {
response.setStatus(status.value());
}
}
// To be picked up by RedirectView
webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, status);
}
// 请求是否被修改
private boolean isRequestNotModified(ServletWebRequest webRequest) {
return webRequest.isNotModified();
}
private void disableContentCachingIfNecessary(ServletWebRequest webRequest) {
if (isRequestNotModified(webRequest)) {
HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
Assert.notNull(response, "Expected HttpServletResponse");
if (StringUtils.hasText(response.getHeader(HttpHeaders.ETAG))) {
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
Assert.notNull(request, "Expected HttpServletRequest");
}
}
}
private String formatErrorForReturnValue(@Nullable Object returnValue) {
return "Error handling return value=[" + returnValue + "]" +
(returnValue != null ? ", type=" + returnValue.getClass().getName() : "") +
" in " + toString();
}
// 处理异步情形下需要获取到的 ServletInvocableHandlerMethod, 这是一个内部类
ServletInvocableHandlerMethod wrapConcurrentResult(Object result) {
return new ConcurrentResultHandlerMethod(result, new ConcurrentResultMethodParameter(result));
}
// 继承该类本身,处理异步的情形
private class ConcurrentResultHandlerMethod extends ServletInvocableHandlerMethod {
//... 省略代码
}
}

          从上面可以看出,该类是 InvocableHandlerMethod 的字类,且提供了 invokeAndHandle 方法,盲猜就是为了补充 HandlerMethod 没有调用目标方法的功能,所以重点可以放在该方法上,可以该方法中通过 invokeForRequest 去调用目标方法,而 invokeForRequest 是它的父类 InvocableHandlerMethod 才有的方法,所以还需要研究下 InvocableHandlerMethod。

InvocableHandlerMethod

public class InvocableHandlerMethod extends HandlerMethod {
private static final Object[] EMPTY_ARGS = new Object[0];
@Nullable
private WebDataBinderFactory dataBinderFactory;
// 用来解析请求参数
private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite();
// 用来获取形参名
private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
// 构造函数
public InvocableHandlerMethod(HandlerMethod handlerMethod) {
super(handlerMethod);
}
public InvocableHandlerMethod(Object bean, Method method) {
super(bean, method);
}
public InvocableHandlerMethod(Object bean, String methodName, Class<?>... parameterTypes)
throws NoSuchMethodException {
super(bean, methodName, parameterTypes);
}
//.. 省略 set 方法
// 获取参数值,然后执行目标方法
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 获取参数值
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
// 传入参数调用目标方法
return doInvoke(args);
}
// 获取参数值
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
}
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
catch (Exception ex) {
// Leave stack trace for later, exception may actually be resolved and handled...
if (logger.isDebugEnabled()) {
String exMsg = ex.getMessage();
if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
logger.debug(formatArgumentError(parameter, exMsg));
}
}
throw ex;
}
}
return args;
}
// 执行目标方法
@Nullable
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
// 父类的 getBridgedMethod 获取到目标方法,通过反射执行
return getBridgedMethod().invoke(getBean(), args);
}
catch (IllegalArgumentException ex) {
assertTargetBean(getBridgedMethod(), getBean(), args);
String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
throw new IllegalStateException(formatInvokeError(text, args), ex);
}
catch (InvocationTargetException ex) {
// Unwrap for HandlerExceptionResolvers ...
Throwable targetException = ex.getTargetException();
if (targetException instanceof RuntimeException) {
throw (RuntimeException) targetException;
}
else if (targetException instanceof Error) {
throw (Error) targetException;
}
else if (targetException instanceof Exception) {
throw (Exception) targetException;
}
else {
throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException);
}
}
}
}

        该类是 ServletInvocableHandlerMethod 的父类,同时又是 HandlerMethod 的字类,该类可以方法的请求参数值,也可以获取到父类的 bean 和目标方法,然后给其传入参数通过反射来执行目标方法。

总结

        从上面的分析可以知道 HandlerMethod 保存了 Controller 对象和目标方法,但是却没有给出执行目标方法的接口。InvocableHandlerMethod  作为 HandlerMethod 字类对其进行了增强,增加了解析请求参数值和执行目标方法的功能,但是它好像跟 Servlet 没有什么关系,没法跟 HTTP 联系起来,所以又有了 ServletInvocableHandlerMethod, 它是对 InvocableHandlerMethod 的进一步增强。ServletInvocableHandlerMethod 借助父类就有了执行目标方法的功能,此外添加了对 @ResponseStatus 的支持,通过 HandlerMethodReturnValueHandlerComposite 来继续操作返回值以及对异步结果的处理,用来跟 Servlet 的 API 对接。

最后

以上就是呆萌钻石为你收集整理的Spring MVC 第二篇 - 关于后端处理器 HandlerMethod的全部内容,希望文章能够帮你解决Spring MVC 第二篇 - 关于后端处理器 HandlerMethod所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(34)

评论列表共有 0 条评论

立即
投稿
返回
顶部