不知道题主是准备怎么写这个框架,我大概写三种处理方式吧:
方案一:不管。其实我之前学 Spring 的时候写过一个小框架,这个问题就没管。当时写的结构也很简单,就是一个方法(带有 @RequestMapping 的)生成一个 handler,然后 DispatherServlet找到合适的 handler 进去 invoke 就完了。当然结果就是只能支持 String 类型的参数,然后让使用这个框架的程序负责类型转换;
方案二:在不管的基础上加一步类型判断和转换。这个其实也很简单,就是加一步 getParameterTypes() 就可以了,然后用到的时候从 String 到相应的类型转换一下。但其实这个改动效果不是特别明显,因为框架太简单本身也处理不了复杂的情况。
方案三:简单介绍一下 Spring MVC 是怎么实现的。它里面有个 HandlerMethod 类,是负责调用适当方法的类。这里面存着一堆需要的属性,方法名、所属的类等等,它并不直接负责 invoke,而是简单对需要的数据做个准备,实际进行 invoke 的是它的两个子类,InvocableHandlerMethod和ServletInvocableHandlerMethod。以前者为例,InvocableHandlerMethod里面有这么一个东西负责参数解析:
private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite();
这个 HandlerMethodArgumentResolverComposite实现了HandlerMethodArgumentResolver这个接口,这个类主要是一个中转站,它里面会有一堆注册过的HandlerMethodArgumentResolver,可以通过 resolveArgument 方法找到合适的 Resolver 进行解析。HandlerMethodArgumentResolver 有很多种,这里就不展开了,但大多数(最主要的)都会继承一个抽象类 AbstractNamedValueMethodArgumentResolver,在这个抽象类底下有一个 final 方法 resolveArgument(这个方法跟那个Composite底下的方法不是同一个),这个方法里面有这样一堆代码:
if (binderFactory != null) {
WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
try {
arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
} catch (ConversionNotSupportedException ex) {
throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),
namedValueInfo.name, parameter, ex.getCause());
} catch (TypeMismatchException ex) {
throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),
namedValueInfo.name, parameter, ex.getCause());
}
}
这里面就是最后的部分了,通过 Spring 的 convertIfNecessary 方法来完成类型转换。(写到这里突然感觉上面说了一堆废话,但是懒得删了,就这么着吧)不过需要注意的是,这只是类型转换这一步,具体的类型判断以及不同情况下的处理要远比写出来的复杂(实际上是一堆不同的类都继承这个抽象类来处理不同的情况),这里就不展开了,如果题主有兴趣的话建议直接去看源码。