前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringMVC源码解析HandlerMethod

SpringMVC源码解析HandlerMethod

作者头像
JavaEdge
发布2021-02-22 14:34:32
3610
发布2021-02-22 14:34:32
举报
文章被收录于专栏:JavaEdgeJavaEdge

被 RequestMapping 注解封印的方法模型类。

封装了关于处理器方法信息的方法和bean类 。 提供了对方法参数,方法返回值,方法注释等方便地访问入口。

该类可以使用bean实例或具有bean名称(例如lazy-init bean,prototype bean)来创建。 使用createWithResolvedBean()获得HandlerMethod实例,被BeanFactory解析过的。

1 字段

代码语言:javascript
复制
	// Object类型,可以是Bean,也可以是个String 的 BeanName
	private final Object bean;
	// 如果是BeanName,就靠它拿到Bean实例
	@Nullable
	private final BeanFactory beanFactory;
	private final Class<?> beanType; // 该方法所属的类
	private final Method method; // 该方法本身
	private final Method bridgedMethod; // 被桥接的方法,如果method是原生的,它的值同method
	// 方法参数的类实例 一个MethodParameter就是一个入参
	private final MethodParameter[] parameters;
	@Nullable
	private HttpStatus responseStatus; // http状态码(负责处理和返回)
	@Nullable
	private String responseStatusReason; // 状态码原因


	// 通过createWithResolvedBean()解析此handlerMethod实例的handlerMethod。
	@Nullable
	private HandlerMethod resolvedFromHandlerMethod;
	// 接口入参上的注解
	@Nullable
	private volatile List<Annotation[][]> interfaceParameterAnnotations;

构造器

代码语言:javascript
复制
	// 它的构造方法众多  此处我只写出关键的步骤
	public HandlerMethod(Object bean, Method method) {
		...
		this.beanType = ClassUtils.getUserClass(bean);
		this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
		this.parameters = initMethodParameters();
		...
		evaluateResponseStatus();
	}
	// 这个构造方法抛出了一个异常NoSuchMethodException 
	public HandlerMethod(Object bean, String methodName, Class<?>... parameterTypes) throws NoSuchMethodException {
		...
		this.method = bean.getClass().getMethod(methodName, parameterTypes);
		this.parameters = initMethodParameters();
		...
		evaluateResponseStatus();
	}
	// 此处传的是BeanName
	public HandlerMethod(String beanName, BeanFactory beanFactory, Method method) {
		...
		// 这部判断:这个BeanName是必须存在的
		Class<?> beanType = beanFactory.getType(beanName);
		if (beanType == null) {
			throw new IllegalStateException("Cannot resolve bean type for bean with name '" + beanName + "'");
		}
		this.parameters = initMethodParameters();
		...
		evaluateResponseStatus();
	}

	// 供给子类copy使用的
	protected HandlerMethod(HandlerMethod handlerMethod) { ... }
	
	// 所有构造都执行了两个方法:initMethodParameters和evaluateResponseStatus

API

createWithResolvedBean

如果所提供的实例包含一个bean的名称,而不是一个对象实例。 则从 bean 工厂解析该名称得到 bean 类(@Component 注解的类),再创建HandlerMethod并返回

代码语言:javascript
复制
	// 初始化该方法所有的入参,此处使用的是内部类HandlerMethodParameter
	// 注意:处理了泛型的~~~
	private MethodParameter[] initMethodParameters() {
		int count = this.bridgedMethod.getParameterCount();
		MethodParameter[] result = new MethodParameter[count];
		for (int i = 0; i < count; i++) {
			HandlerMethodParameter parameter = new HandlerMethodParameter(i);
			GenericTypeResolver.resolveParameterType(parameter, this.beanType);
			result[i] = parameter;
		}
		return result;
	}

	// 看看方法上是否有标注了@ResponseStatus注解(接口上或者父类 组合注解上都行)
	// 若方法上没有,还会去所在的类上去看看有没有标注此注解
	// 主要只解析这个注解,把它的两个属性code和reason拿过来,最后就是返回它俩了~~~
	// code状态码默认是HttpStatus.INTERNAL_SERVER_ERROR-->(500, "Internal Server Error")
	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方法(无set方法)

	// 返回方法返回值的类型  此处也使用的MethodParameter 
	public MethodParameter getReturnType() {
		return new HandlerMethodParameter(-1);
	}
	// 注意和上面的区别。举个列子:比如方法返回的是Object,但实际return “fsx”字符串
	// 那么上面返回永远是Object.class,下面你实际的值是什么类型就是什么类型
	public MethodParameter getReturnValueType(@Nullable Object returnValue) {
		return new ReturnValueMethodParameter(returnValue);
	}

	// 该方法的返回值是否是void
	public boolean isVoid() {
		return Void.TYPE.equals(getReturnType().getParameterType());
	}
	// 返回标注在方法上的指定类型的注解   父方法也成
	// 子类ServletInvocableHandlerMethod对下面两个方法都有复写~~~
	@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);
	}


	// resolvedFromHandlerMethod虽然它只能被构造进来,但是它实际是铜鼓调用下面方法赋值
	@Nullable
	public HandlerMethod getResolvedFromHandlerMethod() {
		return this.resolvedFromHandlerMethod;
	}


	public String getShortLogMessage() {
		return getBeanType().getName() + "#" + this.method.getName() + "[" + this.method.getParameterCount() + " args]";
	}


	// 这个方法是提供给内部类HandlerMethodParameter来使用的~~ 它使用的数据结构还是蛮复杂的
	private List<Annotation[][]> getInterfaceParameterAnnotations() {
		List<Annotation[][]> parameterAnnotations = this.interfaceParameterAnnotations;
		if (parameterAnnotations == null) {
			parameterAnnotations = new ArrayList<>();

			// 遍历该方法所在的类所有的实现的接口们(可以实现N个接口嘛)
			for (Class<?> ifc : this.method.getDeclaringClass().getInterfaces()) {
			
				// getMethods:拿到所有的public的方法,包括父接口的  接口里的私有方法可不会获取来
				for (Method candidate : ifc.getMethods()) {
					// 判断这个接口方法是否正好是当前method复写的这个~~~
					// 刚好是复写的方法,那就添加进来,标记为接口上的注解们~~~
					if (isOverrideFor(candidate)) {
						// getParameterAnnotations返回的是个二维数组~~~~
						// 因为参数有多个,且每个参数前可以有多个注解
						parameterAnnotations.add(candidate.getParameterAnnotations());
					}
				}
			}
			this.interfaceParameterAnnotations = parameterAnnotations;
		}
		return parameterAnnotations;
	}

	
	// 看看内部类的关键步骤
	protected class HandlerMethodParameter extends SynthesizingMethodParameter {
		@Nullable
		private volatile Annotation[] combinedAnnotations;
		...

		// 父类只会在本方法拿,这里支持到了接口级别
		@Override
		public Annotation[] getParameterAnnotations() {
			Annotation[] anns = this.combinedAnnotations;
			if (anns == null) { // 都只需要解析一次
				anns = super.getParameterAnnotations();
				int index = getParameterIndex();
				if (index >= 0) { // 有入参分析
					for (Annotation[][] ifcAnns : getInterfaceParameterAnnotations()) {
						if (index < ifcAnns.length) {
							Annotation[] paramAnns = ifcAnns[index];
							if (paramAnns.length > 0) {
								List<Annotation> merged = new ArrayList<>(anns.length + paramAnns.length);
								merged.addAll(Arrays.asList(anns));
								for (Annotation paramAnn : paramAnns) {
									boolean existingType = false;
									for (Annotation ann : anns) {
										if (ann.annotationType() == paramAnn.annotationType()) {
											existingType = true;
											break;
										}
									}
									if (!existingType) {
										merged.add(adaptAnnotation(paramAnn));
									}
								}
								anns = merged.toArray(new Annotation[0]);
							}
						}
					}
				}
				this.combinedAnnotations = anns;
			}
			return anns;
		}
	}

	// 返回值的真正类型
	private class ReturnValueMethodParameter extends HandlerMethodParameter {
		@Nullable
		private final Object returnValue;
		public ReturnValueMethodParameter(@Nullable Object returnValue) {
			super(-1); // 此处传的-1哦~~~~ 比0小是很有意义的
			this.returnValue = returnValue;
		}
		...
		// 返回值类型使用returnValue
		@Override
		public Class<?> getParameterType() {
			return (this.returnValue != null ? this.returnValue.getClass() : super.getParameterType());
		}
	}
}

继承树

子类都有invoke能力

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/06/04 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 字段
    • 构造器
    • API
      • createWithResolvedBean
        • 继承树
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档