前面三章介绍的都是准备工作,当一切完好之后,dispatcher就可以静静地等待HTTP请求的到来了
任何MVC框架的核心都是Dispatcher,它起到一个中央处理器分发HTTP请求的作用,在我的框架中使用了动态代理模式,这点与springMVC所不同的是,它实现了dispatcher与拦截器的充分解耦,将拦截器和handler做成切片,然后通过调用代理对象的方式去触发拦截器和handler。
这样做当然也是为了今后万一我想要扩展或者修改handler,可以使得代码更灵活方便。
为了方便理解,这里将GothaMVC的流程图放上来。
首先我们定义一个handler的接口出来
package frontController;
import java.lang.reflect.InvocationTargetException;
import modelWrapper.Model;
import webAppContext.HandlerWrapper;
public interface IHandler {
Model doHandler(HandlerWrapper hw) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException;
}
然后去实现这个接口
package frontController;
import java.lang.reflect.InvocationTargetException;
import modelWrapper.Model;
import webAppContext.HandlerWrapper;
public class FixHandler implements IHandler {
@Override
public Model doHandler(HandlerWrapper hw) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Model model=(Model) hw.getM().invoke(hw.getObj(), hw.getArgs());
return model;
}
}
这里是要入参前面所表述过的一个handlerWrapper,这样可以将开发者配置的处理方法和参数以及其所在的类三个信息提供给handler让他执行。
接下来,我们要做的是把拦截器和对handler的调用做成一个切片,代码如下
package frontController;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.ListIterator;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import handlerExecutionChain.HandlerInterceptor;
import modelWrapper.Model;
import webAppContext.ContextLoader;
public class MethodHandler implements InvocationHandler {
private Object target;
private ServletContext sc;
private LinkedList<HandlerInterceptor> chain;
private HandlerInterceptor hi;
private ListIterator<HandlerInterceptor> iter;
private HttpServletRequest req;
private HttpServletResponse resp;
@SuppressWarnings("unchecked")
public MethodHandler(Object target,HttpServletRequest req,HttpServletResponse resp){
this.target=target;
this.req=req;
this.resp=resp;
try {
sc=ContextLoader.createContext();
} catch (Exception e) {
e.printStackTrace();
}
chain=(LinkedList<HandlerInterceptor>) sc.getAttribute("chain");
iter=chain.listIterator();
}
@Override
public Model invoke(Object object, Method method, Object[] arg0) throws Throwable {
if(iter!=null){
while(iter.hasNext()){
hi=iter.next();
if(hi.preHandler(req, resp)){
hi.afterCompletion(req, resp);
}
}
}
Model obj=(Model) method.invoke(target, arg0);
if(iter!=null){
while(iter.hasPrevious()){
hi=iter.previous();
if(hi.postHandler(req, resp)){
hi.afterCompletion(req, resp);
}
}
}
return obj;
}
}
切片做好了之后,我们可以在dispatcher中创建其代理类并通过调用其代理对象达到在调用handler之前和之后触发拦截器的效果,下面是dispatcher的代码
package frontController;
import java.lang.reflect.Proxy;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import modelWrapper.Model;
import viewTemplate.ViewContext;
import viewTemplate.ViewFactory;
import webAppContext.ContextLoader;
import webAppContext.HandlerWrapper;
public class GothamDispatcher {
@SuppressWarnings({ "unchecked" })
protected void doDispatcher(HttpServletRequest doReq,HttpServletResponse doResp) throws Exception{
HttpServletRequest req=doReq;
HandlerWrapper hw=null;
ServletContext sc=ContextLoader.createContext();
ViewContext viewContext=null;
Map<String,HandlerWrapper> urlHandlerMap=(Map<String, HandlerWrapper>) sc.getAttribute("handlers");
String path=req.getServletPath();
if(urlHandlerMap.containsKey(path)){
hw=urlHandlerMap.get(path);
}else{
throw new Exception("no matched handlers!");
}
IHandler handler=new FixHandler();
MethodHandler mh=new MethodHandler(handler,req,doResp);
IHandler proxy=(IHandler) Proxy.newProxyInstance(handler.getClass().getClassLoader(), handler.getClass().getInterfaces(), mh);
//调用代理类对象,拦截器被依次执行
Model model=proxy.doHandler(hw);
if(model!=null&&model.getView()!=null){
String viewName=model.getView();
String viewSuffix=viewName.substring(viewName.length()-3, viewName.length()-1);
switch(viewSuffix){
case "jsp":
viewContext=ViewFactory.getView(ViewFactory.getJsp());
viewContext.render(model, req, doResp);
case "ftl":
viewContext=ViewFactory.getView(ViewFactory.getFreeMarker());
viewContext.render(model, req, doResp);
case ".vm":
viewContext=ViewFactory.getView(ViewFactory.getVelocity());
viewContext.render(model, req, doResp);
}
}
}
}
值得一提的是,dispatcher本身也是门面模式的一种体现。
接着,我们来看看model层的实现,其实这个非常简单,只是把视图名称和一个hashmap封装起来就好了,下面是代码
package modelWrapper;
import java.util.Map;
public class Model {
private String view;
private Map<String,Object> model;
public Model(String view){
this(null,view);
}
public Model(Map<String,Object> model,String view){
this.model=model;
this.view=view;
}
public String getView(){
return view;
}
public Map<String,Object> getModel(){
return model;
}
}
最后说一下,有一些类似于自定义的注释我就没放上来了,只需要告诉大家@Controller是基于类的注解,@Url是基于方法的注解以及二者都是运行时生效。
好了,我的框架到这里就全部介绍完了。其实独立开发感觉还是挺辛苦的,也看了不少源码和博客,尤其是《spring技术内幕》这本书非常不错,给大家推荐一下。
另外,我不保证我的框架可以跑起来啊,哈哈~
还有,本人才疏学浅,在这里也感觉挺献丑的。如果大家发现了什么不足或者错误,一定要帮我指出来哈~