最近研究java Web的MVC,发现一款轻量级的框架,官网描述为类似 Spring 但以 JSON 为主的 Java Web 框架。具体详情见latke github。由于此框架的mvc部分基于Servlet且是对servlet的轻量封装,相对Spring MVC较为简单,就以此框架来学习MVC。
官网提供了一个demo,在latke-demo github
基于Servlet
同Spring MVC类似,latke的web部分基于servlet,在demo项目中的web.xml中找到配置servlet的部分如下:
1 | <servlet> |
可以看到,latke配置的servlet拦截了所有请求,处理请求的类同Spring MVC一样,也叫DispatcherServlet
,所以,我们重点看org.b3log.latke.servlet.DispatcherServlet
这个类。
DispatcherServlet
此类继承了HttpServlet
。并重写了init
和service
方法。我们知道,init
方法是servlet的初始化方法,在项目启动时执行。service
是用来处理请求的方法,当有请求到来时执行。先来看init
。
init
init用于初始化web的资源和配置,源码如下,这里初始化了与web请求相关的几个handler
。对应处理静态资源、注解、请求url和参数解析等。具体在service分析。
1 | SYS_HANDLER.add(new StaticResourceHandler(getServletContext())); |
service
真正处理请求的部分就是遍历上述注册的handler并依次执行。
1 | protected void service(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException { |
StaticResourceHandler
第一个注册的handlar为StaticResourceHandler,用于判断是否为静态资源。若是,直接返回,若否,进入下一个handler处理。
StaticResourceHandler.handle部分代码:1
2
3
4
5
6
7
8 if (StaticResources.isStatic(request)) { //判断是否静态资源
if (null == requestDispatcher) {
//抛出异常,代码就不贴了
}
context.setRenderer(new StaticFileRenderer(requestDispatcher));
return; //返回,直接返回给前台
}
httpControl.nextHandler(); //传给下个handler处理
RequestPrepareHandler
请求预处理,目前只是加了个时间戳,略过。
RequestDispatchHandler
这是处理请求路径的handler,目的是找到与请求路径对应的处理方法(在项目中注解为@RequestProcessor等同于Spring MVC的@Controller,@RequestProcessing等同于@RequestMapping)。
处理过程:
- 在RequestDispatchHandler构造器函数中,已将项目所有标注@RequestProcessing的方法连同url等信息保存于list中。
- 请求路径(在注解中)与上述list进行遍历对比,如发现有对应,就说明找到了处理方法。另外可在请求路径添加类似restful格式的路径参数。如
@RequestProcessing(value = "/a/{b}/c")
样式,在方法声明中需写明此参数,类似void test(String b)
。
若没有找到处理请求的参数,直接404。
需注意:
所有 @RequestProcessor
类已被注册为bean。这步是latke的Ioc部分完成的。暂时先不研究。
ArgsHandler
用于处理方法参数。在上一步中得到了处理请求的方法,这里进一步处理其参数。此handler最重要的任务是提供了若干参数转化器,按先后顺序,每个参数遍历这些转化器,若匹配成功立即返回。
1 | registerConverters(new ContextConvert()); |
前4个设置了HTTPRequestContext
、HttpServletRequest
、HttpServletResponse
、RendererConvert
这4个类的值,分别对应应用上下文(latke自建类)、请求、响应、模板。到时可在参数上直接使用这些类。
JSONObjectConvert
是将请求数据转为json。
PathVariableConvert
匹配除上述参数类型外的其他参数类型。到这里的直接返回匹配成功。再进行相应转化。
AdviceHandler
可以理解类似AOP的handler,主要用于处理@Before
和@After
这两个注解。@Before
用于在方法执行前做一些处理,@After
用于在方法后处理。
看一下源码
1 | public void handle(final HTTPRequestContext context, final HttpControl httpControl) throws Exception { |
### MethodInvokeHandler
不用多说,这个处理器就是处理真正的方法了。直接看源码吧
1 | final Method invokeHolder = result.getProcessorInfo().getInvokeHolder(); //得到方法体 |
返回响应
说完这几个处理器,请求基本是处理完了,下面该返回响应了。让我们回到DispatcherServlet
中。看看最后的result
方法。
1 | public static void result(final HTTPRequestContext context) throws IOException { |