Spring源码阅读之数据自动绑定
来源:互联网 发布:java开源门户网站系统 编辑:程序博客网 时间:2024/06/03 11:55
SpringMVC的调用过程:
DispatcherServlet ——> 根据url找到相应的Controller,反射方式调用Controller相应的方法。
研究下面两种调用方式:
@RequestMapping("/baseType") public User baseType(int count, long id) { User user = new User(); user.setId(id); user.setName("zhang"); return user; } @RequestMapping("/object") public User object(User user) { return user; }
上述代码中,基本类型参数以及Java Bean参数,spring都能进行自动数据绑定。
对于第一种基本数据类型的,假如请求url为http://localhost:8080/user/baseType?count=2&id=5
,url参数能自动绑定到后端方法相应名字的参数,正如上面所说的,Controller的方法是反射调用的,因此通过反射取得的方法是不会保存方法参数的参数名的,那么在反射调用的时候是怎么能够对应参数名进行传递的呢?
通过debug方式阅读spring的源码(请求过程中debug,以及容器启动过程中debug),重点查看了 DefaultParameterNameDiscoverer
, ConstructorResolver
, AspectJAdviceParameterNameDiscoverer
, LocalVariableTableParameterNameDiscoverer
, PrioritizedParameterNameDiscoverer
这几个类发现,spring在启动的时候通过类似asm的方式(没采用asm库)从class文件中读取了方法的参数名,并保存到相应的对象缓存中。这里我还没有仔细研究,我的猜测是class文件是有保存方法参数的参数名的,另外我记得javaassist也是通过读取class文件获取方法的参数名的(但是自己用javac生成的class文件貌似没保存参数名)。后续需要研究一下原生java如何解析class文件内容。
在idea的java compiler中加入 -g:none ,再跑起来,调用url,会报错:
java.lang.IllegalArgumentException: Name for argument type [int] not available, and parameter name information not found in class file either.
由此说明,使用maven编译打包时回把方法的参数名信息加入class文件的,也就是说asm读取参数名字时从class文件获取的。
spring-core中有个ParameterNameDiscoverer就是用来获取参数名的,底层用的是asm解析,但是接口方法的参数名无法得到,即只能是非接口类的方法参数名可以
ParameterNameDiscoverer pnd=new DefaultParameterNameDiscoverer();
String[] parameterNames=pnd.getParameterNames(用反射获取到的方法对象);//返回的就是方法中的参数名列表了
http://bbs.csdn.net/topics/391054482?page=1
Java运行时通过asm读取方法参数名:
http://www.oschina.net/code/snippet_2438265_54195
asm获取参数名的原理??
利用javassist获取java的方法参数名:
http://www.tuicool.com/articles/jMjaIr
java如何获取方法参数名:http://blog.csdn.net/mhmyqn/article/details/47294485
/**
* javac -g:none ,加上这个参数就没有了
* —
* javac -g:vars
* 以及
* mvn clean install 都可以
*/
反射是取不到的,如果在编译时使用默认选项的话。javac带有-g:vars编译参数的话,局部变量及方法形式参数名会在字节码中保存着,但是Java代码是访问不到的。
如果需要抽取字节码中的形式参数名称需要自己去了解JVM字节码规范自己去解析!
对于第二种Java Bean参数自动绑定的,因为是是对象,并不需要上述的参数名,但是需要通过反射方式设值。通过查看源码,发现确实是通过反射方式设值的,但是,正如大家一直所强调的,反射的效率较低,能不用反射尽量别用,但是spring为什么频繁用反射,而且现在每一次请求都是通过反射来赋值,那岂不是效率很低?
通过进一步查看代码发现,虽然第一次请求同过反射方式生成方法,但是所生成的方法会被保存到相应的对象缓存,当请求再次发生,调用相同的方法时,方法并不需要重新通过反射生成,而是直接从缓存中取(其实就是Map或List),不过还是通过此方法代理调用。
其实无论是DispatcherServlet通过反射调用Controller的方法,还是JavaBean参数反射调用赋值,需要反射调用的方法都是只生成一次(之后保存在缓存),而反射调用才是多次重复的。所以我的理解是生成反射方法才是效率低的,而方法的代理调用并不会太影响性能。
- Spring源码阅读之数据自动绑定
- Spring 源码阅读之BeanFactory
- spring源码阅读之BeanFactory
- Spring源码阅读之DefaultListableBeanFactory
- Spring源码阅读之-utils
- Spring 源码之 BeanDefinition阅读
- spring学习之数据绑定
- spring学习之数据绑定
- laravel源码阅读之自动加载功能
- spring源码阅读(四)之BeanFactory
- spring源码阅读(五)之ApplicationContext
- Spring源码阅读 之加载XML配置文件
- Spring源码阅读之Resource接口
- 写优雅代码之阅读spring源码
- Spring源码阅读之DefaultListableBeanFactory系列-SimpleAliasRegistry
- Spring源码阅读之DefaultListableBeanFactory系列-DefaultSingletonBeanRegistry
- Spring之国际化信息MessageSource源码阅读
- Spring源码阅读之-BeanFactory(一)
- 【BZOJ1911】【codevs1318】特别行动队,斜率优化DP
- 改变label的宽度高度值之display:inline-block属性
- Binder框架在Framework层的C++中的使用
- 学习笔记(二)Activity
- 【HDU 1714】【几何】RedField
- Spring源码阅读之数据自动绑定
- 第四章--Notification提醒控件详解
- 复杂链表类的拷贝构造函数的实现(1)
- C++矩阵和向量之间的操作
- java控制控制台里面输出的星号的移动
- (OK) digui-dir-indent.sh——递归
- “插入排序”算法Java语言的实现与详解
- android开发Eclipse首字母和.后面自动提示设置
- 剑指Offer--019-二叉树的镜像