问题
在我们的认知中,源文件(java文件)在被编译成字节码(class文件)时,是不会保留方法名信息的,除非改变javac编译行为,如加入-parameters
、-g
或-g:vars
等等选项,然后反射得到参数名(只对jdk8及以上版本有用)。
但是在spring mvc的控制器中,不用注解、或使用注解@RequestParam
但注解不给出参数名,spring也能够正确地解析请求参数名到对应的方法参数上,如:
@GetMapping("/test")
public String test(@RequestParam int offset,@RequestParam int limit){
...
}
或
@GetMapping("/test")
public String test(int offset,int limit){
...
}
spring能够正确的获取到方法名,它是如何做到的?不知道~~使用的框架的缺点之一就是它在简化使用、抽象概念的同时也屏蔽掉了你对底层原理的认知。你无从得知它是如何实现的,它就是一个黑匣子,你只知道它如何使用即可。
猜想
下面有几个猜想:
猜想一
按照他的说法,maven在编译时默认使用了-g
的选项,因此字节码中会有方法名信息。然而我通过设置-g:none
重新配置maven编译选项,仍然能够进入控制器,不抛出异常。其二,同样是使用maven项目,mybatis没有通过@Param
给出参数名,照样抛出异常。
因此,这应该不是spring能够参数名的原因。
猜想二
来至于:https://stackoverflow.com/questions/50664906/how-can-spring-match-query-parameter-only-by-formal-parameter-name 下的Holger的评论
注解预处理器可以在构建阶段,于编译阶段之前处理源代码,提取参数名,然后添加到字节码中。
这个很有可能。
猜想三
使用三方库,比如ajc、Parameter等等,总之他们有办法就是了。Java 8 Named Method Parameters中就有提到过,spring通过Paramter三方库获取到参数名,而Paramter是通过注解预处理器实现的。
结论
总之,spring就是有办法就是了,而且办法还不止一种,它会尽最大的力来获取正确的参数名:
- if using Java 8 it uses Java 8 reflection
- if classes are compiled in debug mode, parameter name is present and spring uses it, same if ajc (aspectJ compiler) has been used)
- it can eventually uses @Param annotations
- it uses the type if not ambiguous
总之。。。黑匣子会用就行了。。。
参考
how can spring get args name from the method
How can Spring match query parameter only by formal parameter name?
Java 8 Named Method Parameters