Argo源码阅读(六):ArgoDispatcher
来源:互联网 发布:朵朵淘宝小号批发 编辑:程序博客网 时间:2024/04/28 05:54
回到最顶层的调用ArgoFilter.init(),Argo.init()初始化了ArgoDispatcher,ArgoFilter初始化完毕。
ArgoFilter.doFilter实现过滤功能
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpReq = (HttpServletRequest) request; HttpServletResponse httpResp = (HttpServletResponse) response; dispatcher.service(httpReq, httpResp); }
只是简单地交给ArgoDispatcher处理。
接口ArgoDispatcher添加了@ImplementedBy(DefaultArgoDispatcher.class)注解,@ImplementedBy注解设置默认的实现类和bind(ArgoDispatcher.class).to(DefaultArgoDispatcher.class)的结果是等价的。
下面介绍DefaultArgoDispatcher
@Inject public DefaultArgoDispatcher(Argo argo, Router router, StatusCodeActionResult statusCodeActionResult, MultipartConfigElement config) { this.argo = argo; this.router = router; this.statusCodeActionResult = statusCodeActionResult; this.config = config; this.logger = argo.getLogger(this.getClass()); logger.info("constructed.", this.getClass());}
可以发现构造函数添加了@Inject注解,参数是通过注入实现实例化的。
@Override protected void configure() {… bind(MultipartConfigElement.class) .toProvider(DefaultMultipartConfigElementProvider.class) .in(Singleton.class);… }
在Argo.init()中,ArgoDispatcher是在buildInjector之后构造的,构造注解器的参数Module中有ArgoModule。ArgoModule中对DefaultArgoDispatcher的接口和实现类进行了bind。
DefaultArgoDispatcher的service方法
public void service(HttpServletRequest request, HttpServletResponse response) { ArgoRequest argoRequest = new ArgoRequest(request, config); try { BeatContext beatContext = bindBeatContext(argoRequest, response); route(beatContext); } finally { Closeables.closeQuietly(argoRequest); } }
private BeatContext bindBeatContext(HttpServletRequest request, HttpServletResponse response) { Context context = new Context(request, response); localContext.set(context); BeatContext beat = argo.injector().getInstance(defaultBeatContextKey); // 增加默认参数到model beat.getModel().add("__beat", beat); context.setBeat(beat); return beat; }
DefaultBeatContext bind(BeatContext.class) .annotatedWith(ArgoSystem.class) .to(DefaultBeatContext.class);
实现了BeatContext接口的有两个类,BeatContextWrapper和DefaultBeatContext。BeatContextWrapper比较简单,DefaultBeatContext则通过注解加入了其它部分。
@ArgoSystempublic class DefaultBeatContext implements BeatContext { @Inject public DefaultBeatContext(HttpServletRequest request, HttpServletResponse response, Model model, ClientContext clientContext, ServletContext servletContext) { this.request = request; this.response = response; this.model = model; this.clientContext = clientContext; this.servletContext = servletContext; }}
Route():
Router接口添加了@ImplementedBy注解
@ImplementedBy(DefaultRouter.class)public interface Router { public ActionResult route(BeatContext beat);}
//DefaultArgoDispatcher.route() private void route(BeatContext beat) { try { ActionResult result = router.route(beat); if (ActionResult.NULL == result) result = statusCodeActionResult.getSc404(); result.render(beat); } catch (Exception e) { statusCodeActionResult.render405(beat); } finally { localContext.remove(); } }
DefaultRouter构造时将会初始化一个actions变量
@Inject public DefaultRouter(Argo argo, @ArgoSystem Set<Class<? extends ArgoController>> controllerClasses, @StaticActionAnnotation Action staticAction) { this.argo = argo; argo.getLogger().info("initializing a %s(implements Router)", this.getClass()); this.actions = buildActions(argo, controllerClasses, staticAction); argo.getLogger().info("%s(implements Router) constructed.", this.getClass()); }
在buildActions中将会对所有的Controller通过ControllerInfo调用analyze
List<Action> buildActions(Set<ArgoController> controllers, Action staticAction) { ... for (ArgoController controller : controllers) { ControllerInfo controllerInfo = new ControllerInfo(controller); List<ActionInfo> subActions = controllerInfo.analyze(); ... } }
analyze会找到所有符合条件的Method(返回类型是ActionResult的public方法),然后构造ActionInfo。ActionInfo构造是会找到方法的前置/后置拦截器,参数类型,参数名,确定GET/POST类型,计算order。
public RouteResult matchAndInvoke(RouteBag bag) { if (!actionInfo.matchHttpMethod(bag)) return RouteResult.unMatch(); Map<String, String> uriTemplateVariables = Maps.newHashMap(); boolean match = actionInfo.match(bag, uriTemplateVariables); if (!match) return RouteResult.unMatch(); // PreIntercept for(PreInterceptor preInterceptor : actionInfo.getPreInterceptors()) { ActionResult actionResult = preInterceptor.preExecute(bag.getBeat()); if (ActionResult.NULL != actionResult) return RouteResult.invoked(actionResult); } ActionResult actionResult = actionInfo.invoke(uriTemplateVariables); // PostIntercept for(PostInterceptor postInterceptor : actionInfo.getPostInterceptors()) { actionResult = postInterceptor.postExecute(bag.getBeat(), actionResult); } return RouteResult.invoked(actionResult); }
preExecute如果返回NULL则直接显示,否则执行后续的interceptor。
Action.invoke则调用对应的Controller中匹配路径的方法。
渲染页面,实现ActionResult接口的比较多。404,405,redirect,redirect301,VelocityViewResult,InnerPrintWriter,DefaultStaticResult。
根据返回的ActionResult类型执行对应的render方法渲染页面
- Argo源码阅读(六):ArgoDispatcher
- Argo源码阅读(一):Jetty
- Argo源码阅读(四):Servlet过滤器
- Argo源码阅读(五):Convention
- Argo源码阅读(二):Controller的使用
- Argo源码阅读(三):Google-guice依赖注入框架
- WINVNC源码阅读(六)
- lite源码阅读(六)总结
- ZooKeeper源码阅读(六):JUTE
- AFNetworking 3.0 源码阅读笔记(六)
- 内核源码阅读(六)内核线程
- Tomcat 源码阅读(六)Adapter
- STL源码阅读(六)
- tomcat源码阅读步骤六
- spring源码阅读(六)之BeanDefinition的载入
- Tomcat源码阅读系列(六)类加载器
- Flask源码阅读(六)——Flash消息
- Memcache-Java-Client-Release源码阅读(之六)
- Codeforces Round #185 (Div. 1) && (Div. 2)
- Android Animation学习笔记
- zoj1008 gnome tetravex 很久之前的dfs
- A Knight's Journey(简单dfs)
- 关于android分辨率兼容(屏幕适配)问题
- Argo源码阅读(六):ArgoDispatcher
- 修改/etc/fstable自动挂载磁盘设备
- jquery的treeview插件 调用样例(动态数据)
- lr-关联
- hdu 1978 How many ways(DP | 记忆化搜索)
- android 屏幕适配问题
- 配色基础:你要懂的色彩悄悄话
- Android布局中长度单位的深入研究
- JavaScript: The Definitive Guide 权威指南,读书笔记(三)