58同城开源的轻量级web框架 https://github.com/58code/Argo
有人说,为了这么一个小框架,花费这么长时间阅读,还分成这么多篇博客,小题大做。
仁者见仁智者见智吧,大家在学习过程中都有自己的一套方式方法,适合自己的就是最高效的。框架工具无分大与小、好与坏,人家花了大量时间琢磨研究这样一个框架,并且大范围运用起来,肯定是有道理的,至于能吃得多透,还得结合各自的实际经验,能产生共鸣是最好,没准咱还能想到作者所想不到的。
吐个槽先,Guice的注解风格提高了调试成本,我都找不到在哪实例化的ArgoDispatcher,只能看Type hierarchy,哪个实现类有Guice的实现注解。麻烦死了。。。。
DefaultArgoDispatcher 是默认的 ArgoDispatcher 实现,有注解 @Singleton。但是看到这里也没看到进行的controller实例化,以及url与方法的映射绑定。如果不熟悉Guice就直接来看Argo的代码,坑还是挺多的。秘密在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 是通过Guice对参数列表进行实例注射,因此参数中实例的构造方法也都会执行一遍。Router 的默认实现是DefaultRouter,构造方法中有
this.actions = buildActions(argo, controllerClasses, staticAction);
actions?不是controller么?参数列表中的@ArgoSystem 和 @StaticActionAnnotation又是怎么回事,又是坑啊。经过一番整理,结果如下:
@ArgoSystem 和 @StaticActionAnnotation 这两个解标注了Guice的 @BindingAnnotation 参考Guice文档,用于Argo内部注入用。com.bj58.argo.inject.ArgoModule 中可以看到两个方法
@Provides @ArgoSystem @Singleton private Set<Class<? extends ArgoController>> provideControllerClasses() { return argo.getControllerClasses(); } bind(Action.class).annotatedWith(StaticActionAnnotation.class) .to(StaticFilesAction.class);
因此找到了@StaticActionAnnotation的对应实现类StaticFilesAction,Set<Class<? extends ArgoController>>类型的提供者,构造方法中的groupConvention.currentProject().controllerClasses();
于是继续向groupConvention去找,终于找到了DefaultGroupConvention,里面对框架环境的描述已经非常详细了。
@SuppressWarnings("unchecked") Set<Class<? extends ArgoController>> parseControllers(GroupConventionAnnotation groupConventionAnnotation) { Set<Class<?>> classSet = ClassUtils.getClasses(groupConventionAnnotation.groupPackagesPrefix()); Pattern controllerPattern = Pattern.compile(groupConventionAnnotation.controllerPattern()); ImmutableSet.Builder<Class<? extends ArgoController>> builder = ImmutableSet.builder(); for (Class<?> clazz : classSet) if (applyArgoController(clazz, controllerPattern)) builder .add((Class<? extends ArgoController>) clazz) .build(); return builder.build(); }
看到这个方法了吧
1. Set<Class<?>> classSet = ClassUtils.getClasses(groupConventionAnnotation.groupPackagesPrefix()); 把符合约定前缀包名的Class都扫出来,默认是com.bj58.argo
2. Pattern controllerPattern = Pattern.compile(groupConventionAnnotation.controllerPattern());
读取controller的约定包名,可以是一个正则表达式,默认是.*\\.controllers\\..*Controller
3. 后面就是遍历class,校验每个class是否合法,符合controller规范。把符合规范的放到一个不可变Set中,这个过程是通过Guava来做的。
还有一个很重要的功能,就是模板变量式的路径配置(一种语法糖)。下面多贴点代码,没什么技巧、难点,应该一看就懂。比如首我定义两个KV,分别是 a=/tmp,b={a}/log,那么经过下面代码的解析,最终值就会变成 a=/tmp,b=/tmp/log
private Map<String, String> parseGroupConventionPath(GroupConventionAnnotation groupConventionAnnotation , ProjectConvention projectConvention) { Map<String, String> paths = ImmutableMap.<String, String>builder() .put(PACKAGES_PREFIX, groupConventionAnnotation.groupPackagesPrefix()) .put(PROJECT_ID, projectConvention.id()) .put(GROUP_CONFIG_FOLDER, groupConventionAnnotation.groupConfigFolder()) .put(GROUP_LOG_FOLDER, groupConventionAnnotation.groupLogFolder()) .build(); return matchPath(paths); } static Map<String, String> matchPath(Map<String, String> paths) { Map<String, String> values = Maps.newHashMap(); Map<String, String> templates = Maps.newHashMap(); Map<String, String> result = Maps.newHashMap(); classify(paths, values, templates); while (values.size() > 0) { values = migrate(values, templates, result); } if (templates.size() > 0) throw ArgoException.newBuilder("GroupConventionAnnotation contains nested expression") .addContextVariables(templates) .build(); return result; } /** * 将定值数据保存到结果数据集合,并将模板数据用定值数据进行替换,并返回替换后的定值 * @param values 定值数据集合 * @param templates 模板数据集合 * @param result 结果数据集合 * @return 由模板替换后生成的定值数据 */ static Map<String, String> migrate(Map<String, String> values, Map<String, String> templates, Map<String, String> result) { result.putAll(values); for (Map.Entry<String, String> templateItem : templates.entrySet()) { String v = templateItem.getValue(); for (Map.Entry<String, String> valueItem : values.entrySet()) { String exp = '{' + valueItem.getKey() + '}'; if (v.contains(exp)) v = v.replace(exp, valueItem.getValue()); } if (!v.equals(templateItem.getValue())) templateItem.setValue(v); } Map<String, String> newValues = Maps.newHashMap(); Map<String, String> newTemplates = Maps.newHashMap(); classify(templates, newValues, newTemplates); templates.clear(); templates.putAll(newTemplates); return newValues; } /** * 分类数据,若路径中存在"{",刚归类到模板数据,否则归类到定值数据 * @param paths 路径数据集合 * @param values 定值数据集合 * @param templates 模板数据集合 */ static void classify(Map<String, String> paths, Map<String, String> values, Map<String, String> templates) { for (Map.Entry<String, String> entry : paths.entrySet()) { if (entry.getValue().contains("{")) templates.put(entry.getKey(), entry.getValue()); else values.put(entry.getKey(), entry.getValue()); } }
今天的最后说的是页面模板,Argo的抽象接口是ViewFactory,唯一需要实现的方法是ActionResult create(String viewName);
/** * 提供View工厂,默认采用velocity模板 */ @ImplementedBy(VelocityViewFactory.class) public interface ViewFactory { ActionResult create(String viewName); }
AbstractController 中的 view(String viewName) 方法是页面生成渲染时需要用到的,里面调用viewFactory.create(viewName);来实现。
所以如果我们使用Argo,又不想用velocity做页面模板,就需要再实现一套ViewFactory,把@ImplementedBy注解中的Class改成自己的就ok了。
这个类里面是velocity的一些配置,都是常见的,也不多说明了。
相关推荐
Argo,源自58同城,是一款强大的开源Web框架,专为构建高性能、高可扩展性的Web应用而设计。基于Java语言,Argo在58同城内部广泛应用于各种Web站点,包括移动端和WAP访问,展现出了其在处理大规模并发和复杂业务场景...
【58同城开源框架】是58同城公司推出的一款开源技术框架,旨在为开发者提供高效、稳定、可扩展的开发工具。这个框架凝聚了58同城在互联网服务领域的技术积累,体现了其对软件工程的最佳实践,有助于提升开发效率,...
Argo是开源的web框架,目前Argo支撑着58同城几乎所有的web站点,包括wap和手机端的访问等,现在wf每天处理10亿级的请求。经过长时间的运作与运行,证明Argo是一个可靠的、高效的web框架。 Argo在wf做了大量优化和...
ArgoUML-0.26开源.exe 推荐下载
- **自研系统**:开发了专门的图片存储系统,以及一套完整的开发框架(包括Web框架Argo和服务框架Gaea),大大降低了站点和服务的开发成本。 #### 四、更大流量挑战及解决方案 - **面临的新挑战**:如何应对更高的...
ArgoUML是一款开源的UML(统一建模语言)工具,主要版本为0.14,被封装在名为"ArgoUML-0.14.zip"的压缩包文件中。这个工具允许用户创建、编辑和管理UML模型,是软件开发过程中的一个重要辅助工具,尤其对于系统分析...
代码超级干净,可以很容易地定制,很容易转化为任何类型的web应用程序,包括自定义管理面板,数据分析仪表盘,电子商务后端、CMS、CRM或任何SASS面板。 主要特色 响应布局(台式电脑、平板电脑、移动设备) 用Bootstrap...
ARGO UML(ArgoUML)是一款基于Java开发的开源统一建模语言(UML)工具。UML是一种广泛用于软件系统分析和设计的标准化建模语言,它提供了图形化的表示方法,帮助开发者理解和交流软件系统的结构和行为。而argouml....
- 开源:ArgoUML是开源项目,这意味着任何人都可以自由地下载、使用、修改和分发该软件,这促进了社区的参与和创新。 关于手册的版权,它采用了开放出版许可证(Open Publication License, OPL),这允许用户在满足...
ArgoUML是一款开源的统一建模语言(UML)设计工具,专为软件开发者提供图形化界面,以便创建和管理UML模型。这款软件的独特之处在于它支持与PHP的集成,使得Web开发者也能利用UML进行项目规划和设计。 UML是一种...
**五、ArgoUML与其他工具比较** ArgoUML以其开源、免费和跨平台的优势,与商业UML工具(如IBM Rational Rose或Enterprise Architect)相竞争。虽然可能在功能和用户体验上有所不足,但对于个人开发者或小型团队来说...
ArgoUML是一款开源的计算机辅助软件工程(CASE)工具,主要用于统一建模语言(UML)的建模。它提供了丰富的功能,让用户能够便捷地设计、创建和管理UML模型。这款轻量级的应用程序在Java平台上运行,因此具有跨平台的...
ARGO入门手册1为用户提供了一个全面了解ARGO项目和ARGO数据的指南,包括ARGO浮标的工作原理、ARGO数据的类型和获取方式、ARGO数据的应用等方面。该手册旨在帮助用户更好地理解和使用ARGO数据,从而推动全球海洋研究...
ArgoCD 是一个开源项目,专门设计用于Kubernetes的持续交付。它提供了一种声明性的方式来管理K8s资源,使开发者能够将应用程序的状态与Git存储库中的定义保持一致。这使得整个部署过程变得可审计、透明且易于管理。...
ArgoUML 是一个开源的统一建模语言(UML)建模工具,专为软件开发者和设计师提供便捷的UML模型创建环境。该工具支持多种编程语言的代码自动生成,包括C++、C、Java、PHP、SQL和C#等,极大地提升了开发效率和代码一致...
zooviewer zookeeper web ui written in java.jsut like node-zk-web 这是一个查看zookeeper节点并可以...1,基于58开源的web框架Argo,全应用无一个配置文件。详见. 2,页业端用了jquery-tree ,方便查看zk的树状节点.
argouml一款很好的开源uml工具 中文版的
ArgoUML是一款开源的、基于Java编写的统一建模语言(UML)设计工具,适用于多种操作系统,包括Mac OS X。它提供了全面的UML支持,使得软件开发者和系统分析师可以方便地创建、编辑和管理各种UML模型。在Mac平台上,...
ArgoUML是一款开源的统一建模语言(Unified Modeling Language, UML)工具,支持大部分UML 1.4标准中的图类型。它适用于软件设计师、开发人员和其他相关人员在软件开发生命周期中的需求分析、设计阶段进行系统建模。...
**ArgoUML** 是一个基于Java开发的开源UML(统一建模语言)绘图工具,它允许用户在各种操作系统上创建、编辑和管理UML模型。由于其跨平台特性,无论是在Windows、Linux还是Mac OS X系统上,用户都能方便地使用Argo...