SpringMVC的Controller是如何将参数和前端传来的数据一一对应的

Spring接收前端传来的参数之后,是如何把前端参数对应到方法里的参数的?
比如

public String hello(String hello, @RequestParam(value = "world") String world, String end) {
    return hello + world + end;
}

这个方法,假如url是http://localhost:8080/hello?hello=hi&word=spring&end=!
那么spring就可以把hello方法里的hello,world,end一一对应上。
world这个参数能对应上还可以理解,因为有个注解@RequestParam里写了参数名。
但是hello`,end是如何找到对应参数的?java在编译之后他的参数名就没了,spring如何知道第一个参数是hello,第三个参数是end的?

我问题的意思是...spring是如何实现参数的对应的?如何知道hello()方法中的参数'hello,end'这两个的参数名字的,java编译之后就没有参数名字了

阅读 7.9k
5 个回答

大家都没理解我问的问题,可能是我提问的技巧还不是很好,不过我已经找到答案了。
我想问的是假如在Controller里的方法参数没有@RequestParam注解的时候,Spring是如何通过反射调用这个方法的,因为java的反射是无法获取参数名字的,无法获取参数名字就以为着无法把前端传来的参数找到方法中正确的参数。
现在我找到答案了:
在Spring中的类DefaultParameterNameDiscoverer (<version>2.0.2.RELEASE</version>):

public class DefaultParameterNameDiscoverer extends PrioritizedParameterNameDiscoverer {

    private static final boolean kotlinPresent =
            ClassUtils.isPresent("kotlin.Unit", DefaultParameterNameDiscoverer.class.getClassLoader());

    public DefaultParameterNameDiscoverer() {
        if (kotlinPresent) {
            addDiscoverer(new KotlinReflectionParameterNameDiscoverer());
        }
        addDiscoverer(new StandardReflectionParameterNameDiscoverer());
        addDiscoverer(new LocalVariableTableParameterNameDiscoverer());
    }

}

这个类是设置查找参数名方法的类,这里有三种
1.KotlinReflectionParameterNameDiscoverer:
看代码是判定是否为Kotlin,如果是就用这种,对于Kotlin我也不熟就没有细看
2.StandardReflectionParameterNameDiscoverer:
这是用java原生自带的反射原理获取参数名字

private String[] getParameterNames(Parameter[] parameters) {
        String[] parameterNames = new String[parameters.length];
        for (int i = 0; i < parameters.length; i++) {
            Parameter param = parameters[i];
            if (!param.isNamePresent()) {
                return null;
            }
            parameterNames[i] = param.getName();
        }
        return parameterNames;
    }

3.LocalVariableTableParameterNameDiscoverer
这是spring通过asm读取class字节码来获取方法的参数名字,具体的解释可以查看资料

所以Spring实际上是通过反射或者字节码读取获取方法的参数的名字的。
另外我这个Spring的源码2.0.2.RELEASE,由于2.X.X以上的版本要求jdk环境是1.8以上。在2.X.X一下的版本DefaultParameterNameDiscoverer类会先判断环境是否是1.8以上,如果是,在会调用
StandardReflectionParameterNameDiscoverer这个原生反射查找参数名的类,因为这个方法要jdk1.8以后才支持。

spring对request参数做了处理,用request中的参数去匹配方法的参数,如果name一样,就会把值传过去,好像是跟顺序没关系的,这点你可以试一下。
而你参数上的注解,是用来匹配name值不同的情况的,如果请求的参数名称和方法参数名称不同,就可以用这个注解。

添加一个拦截器,在映射这个方法之前,对这个方法进行反射处理,获取方法的参数及名称,然后在用发射调用这个方法。差不多是这样,具体要看spring源码才能知道。

你把名字改了就知道了

@RequestParam

位于RequestParamMethodArgumentResolver和RequestParamMapMethodArgumentResolver 中

推荐问题