深入理解SpringMVC 参数映射

深入理解SpringMVC 参数映射

写在前面:
由于公司目前系统07年开始开发的,完全由servlet+htm开发的,无设计模式,全if else ,while 构成,有的客户还是用JDK1.5,上过一次spring报了100多个bug,又下架了。现在开始自己写类似spring MVC ,BeanFactory,Aop,myBatis框架。在开发的过程中,对SpringMVC,myBatis等框架进行了研究。我的新框架是简单的实现,基本够用。
本次先写对SpringMVC参数映射的一点认识。

  • 一、Spring MVC请求过程
  • 二、路径到Controller方法映射
  • 三、方法参数映射
  • 四、总结

引入

http://127.0.0.1/login?username=admin&password=!# ! <script type="math/tex" id="MathJax-Element-4">!</script>#!#

public String login(String username,String password){

}

SpringMVC是如何把参数名称username,password对应上,且把值传给对应方法的?
带着上面的问题,逐步来了解

一、Spring MVC请求过程

先看一下,请求过程的堆栈:
从doService 一路到 LocalVariableTableParameterNameDiscoverer.getParameterNames,再调用 ClassReader 读取class文件解析出参数名称。
这里写图片描述
请求概要 时序图
这里写图片描述
接上图
这里写图片描述

从图二开始解析参数,
图二中的 ParameterNameDiscoverer 是接口,LocalVariableTableParameterNameDiscoverer是其实现类。

二、路径到Controller方法映射
略……

重点开始:
三、方法参数映射
LocalVariableTableParameterNameDiscoverer.java

@Override
    public String[] getParameterNames(Method method) {
        Method originalMethod = BridgeMethodResolver.findBridgedMethod(method);
        Class<?> declaringClass = originalMethod.getDeclaringClass();
        Map<Member, String[]> map = this.parameterNamesCache.get(declaringClass);
        if (map == null) {
            map = inspectClass(declaringClass);
            this.parameterNamesCache.put(declaringClass, map);
        }
        if (map != NO_DEBUG_INFO_MAP) {
            return map.get(originalMethod);
        }
        return null;
    }

先从参数缓存中查找,

Map<Member, String[]> map = this.parameterNamesCache.get(declaringClass);

如果没有解析过(本次重点方法)

map = inspectClass(declaringClass);

详细方法如下:(我去掉了注释和异常日志打印)

private Map<Member, String[]> inspectClass(Class<?> clazz) {
        InputStream is = clazz.getResourceAsStream(ClassUtils.getClassFileName(clazz));
        if (is == null) {           
            return NO_DEBUG_INFO_MAP;
        }
        try {
            ClassReader classReader = new ClassReader(is);
            Map<Member, String[]> map = new ConcurrentHashMap<Member, String[]>(32);
            classReader.accept(new ParameterNameDiscoveringVisitor(clazz, map), 0);
            return map;
        } catch (IOException ex) {}
          catch (IllegalArgumentException ex) {}
        finally {
            is.close();         
        }
        return NO_DEBUG_INFO_MAP;
    }

分析:
1 加载class文件流
2 构造ClassReader
3 调用ClassReader.accept
具体对应方法:
public void accept(final ClassVisitor classVisitor,final Attribute[] attrs, final int flags)

接着调用 :
private int readMethod(final ClassVisitor classVisitor,final Context context, int u)
这个方法中,读取class文件,根据java规范解析该文件,获取方法名称,参数类型,参数名称
至此,获取到对应的Controller对应方法的参数名称 如:username,password,
再调用request.getParameter(“username”)获取参数值
一路返回至 InvocableHandlerMethod.doInvoke(),MappingRequest对应的方法

四、总结
由于时间紧迫,语言表达能力有限,仅供参考。
等稍空闲再写 ClassReader读取过程。

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值