Spring MVC为何好使?
首先使用上需明确:Spring MVC好使但它并不依赖于-parameters参数,也不依赖于-g这个编译参数,因为它是借助ASM来实现的~
spring-core中有个ParameterNameDiscoverer就是用来获取参数名的,底层用的是asm解析,但是接口方法的参数名无法得到,即只能是非接口类的方法参数名可以。
从文首的例子可以看出Spring MVC它最终依赖的是DefaultParameterNameDiscoverer去帮忙获取到入参名,看看这块代码:
// @since 4.0 public class DefaultParameterNameDiscoverer extends PrioritizedParameterNameDiscoverer { public DefaultParameterNameDiscoverer() { if (!GraalDetector.inImageCode()) { if (KotlinDetector.isKotlinReflectPresent()) { addDiscoverer(new KotlinReflectionParameterNameDiscoverer()); } addDiscoverer(new StandardReflectionParameterNameDiscoverer()); addDiscoverer(new LocalVariableTableParameterNameDiscoverer()); } } }
DefaultParameterNameDiscoverer它就是一个责任链模式的体现,靠它添加进来的实现类来处理,也就是这哥俩:
StandardReflectionParameterNameDiscoverer:依赖于-parameters才会有效(有java版本要求和编译参数要求)
LocalVariableTableParameterNameDiscoverer:基于ASM实现,无版本和编译参数要求~
备注:Spring使用ASM无需额外导包,因为自给自足了:
MyBatis为何不好使?
首先使用上需要明确这一点:MyBatis
是通过接口跟SQL语句绑定然后生成代理类来实现的。
既然有了强大的ASM
,那么问题来了:难道ASM
也帮不到MyBatis
来简化开发?
看看我给的这个例子或许你就能明白了并不能怪MyBatis
呀:
public class MainTest2 { // 使用工具方法获取Method的入参名字~~~ public static void main(String[] args) throws SecurityException, NoSuchMethodException, IOException { Method method = MainTest2.class.getDeclaredMethod("testArgName", String.class, Integer.class); String[] methodParamNames = getMethodParamNames(method); // 打印输出 System.out.println(StringUtils.arrayToCommaDelimitedString(methodParamNames)); } } // 接口方法 interface MyDemoInterface{ String testArgName(String name, Integer age); }
输出:
null,null
可见即使强如ASM,也是木有办法直接获取到接口的形参名的。
这是可以被理解的,因为接口方法不是实际方法,它的形参名是会被实现类覆盖的,所以接口方法的形参名意义不大~
Tips:接口上的default方法和static方法的参数名是可以被正常获取到的,有兴趣的小伙伴可以自己动手试试~
至于ASM为何对接口无效,其根本原因我展示一下字节码一看便清楚了:
因为抽象方法没有方法体,也就没有局部变量,自然也就没有局部变量表了,所以即使使用ASM也拿不到它的变量名~
说明:在Java8后使用-parameter参数即使是接口,是可以直接通过Method获取到入参名的,这个对MyBatis是好用的。当然为了保证兼容性,个人建议还是乖乖使用@Param注解来指定吧~
至此,我有理由相信小伙伴是和我一样,彻底搞明白为何Spring MVC可以,但MyBatis却不可以这个疑问了吧~~~
总结
本文深入到字节码处分析了这个有可能也是困扰了你很久的问题(问题如题),希望为你答疑解惑了。同时也介绍了ASM的基本用法,或许对你后续理解别的框架会有所帮助~