文档

§介绍 Play 2

此页面也适用于 Play 3,于 2023 年 10 月发布。

自 2007 年以来,我们一直在努力使 Java Web 应用程序开发变得更容易。Play 最初是 Zenexity(后来成为 Zengularity,最终被 Fabernovel 收购)的内部项目,并深受我们进行 Web 项目的方式的影响:专注于开发人员效率,尊重 Web 架构,并从一开始就使用一种全新的打包约定方法——打破所谓的 JEE 最佳实践,只要有意义。

2009 年,我们决定将这些想法作为开源项目与社区分享。我们立即收到了非常积极的反馈,该项目获得了很大关注。如今——经过多年的积极公开开发——Play 拥有多个版本,一个活跃的社区,拥有超过 10,000 人,并且在全球范围内运行的应用程序数量不断增长。

将项目开放给全世界当然意味着更多反馈,但也意味着发现和了解新的用例、所需功能以及发掘在原始设计及其假设中未明确考虑的错误。在这些年来,我们一直在努力解决 Play 作为开源项目的此类问题,以及集成新功能以支持更广泛的场景。随着项目的不断发展,我们从社区和自身经验中学到了很多——在越来越复杂和多样化的项目中使用 Play。

与此同时,技术和 Web 继续发展。Web 已成为所有应用程序的中心点。HTML、CSS 和 JavaScript 技术快速发展——使服务器端框架几乎无法跟上。整个 Web 架构正在快速转向实时处理,而当今项目配置文件的新兴需求意味着 SQL 无法再作为唯一的数据库技术。在编程语言级别,我们见证了一些重大的变化,包括 Scala 等几种 JVM 语言越来越受欢迎。

这就是我们创建 Play 2 的原因,一个面向新时代的全新 Web 框架。

§为异步编程而构建

当今的 Web 应用程序正在集成更多并发实时数据,因此 Web 框架需要支持完整的异步 HTTP 编程模型。我们最初设计 Play 来处理具有许多短暂请求的经典 Web 应用程序。但现在,事件模型是通过 Comet、长轮询和 WebSockets 进行持久连接的最佳方式。

Play 2 从一开始就以每个请求都可能长时间存在的假设为基础进行架构。但这还不是全部:我们还需要一种强大的方法来调度和运行长时间运行的任务。基于 Actor 的模型无疑是当今处理高度并发系统的最佳模型,而 Java 和 Scala 都可用的该模型的最佳实现是 Akka——因此它将被纳入。Play 2 为 Play 应用程序提供了原生 Akka 支持,使其能够编写高度分布式系统。

Play 3 使用 Pekko 替换了 Akka,更多详细信息请参见 此处

§专注于类型安全

使用静态类型编程语言编写 Play 应用程序的一个好处是,编译器可以检查代码的一部分。这不仅有助于在开发过程的早期发现错误,而且也使在涉及大量开发人员的大型项目中更容易协作。

在 Play 2 中添加 Scala,我们明显受益于更强大的编译器保证——但这还不够。在 Play 1.x 中,模板系统是动态的,基于 Groovy 语言,编译器无法为您做太多。因此,模板中的错误只能在运行时检测到。验证控制器中的粘合代码也是如此。

在 2.0 版本中,我们真的想进一步推动 Play 在编译时检查大部分代码的想法。这就是为什么我们决定使用基于 Scala 的模板引擎作为 Play 应用程序的默认引擎——即使对于使用 Java 作为主要编程语言的开发人员也是如此。这并不意味着您必须成为 Scala 专家才能在 Play 2 中编写模板,就像您在 Play 1.x 中编写模板时并不真正需要了解 Groovy 一样。

在模板中,Scala 主要用于导航您的对象图以显示相关信息,其语法非常接近 Java 的语法。但是,如果您想利用 Scala 的强大功能来编写高级模板抽象,您将很快发现 Scala 作为一种面向表达式和函数式的语言,非常适合模板引擎。

这不仅适用于模板引擎:路由系统也经过了完全类型检查。Play 2 检查您的路由描述,并验证一切是否一致,包括反向路由部分。

完全编译的一个很好的副作用是,模板和路由文件将更容易打包和重用。您还将在运行时获得这些部分的显著性能提升。

§对 Java 和 Scala 的原生支持

在 Play 项目的历史早期,我们开始探索使用 Scala 编程语言编写 Play 应用程序的可能性。我们最初将这项工作引入作为一个外部模块,以便能够自由地进行实验,而不会影响框架本身。

将 Scala 正确集成到基于 Java 的框架中并非易事。考虑到 Scala 与 Java 的兼容性,人们可以很快实现一个简单的初始集成,它只是使用 Scala 的语法而不是 Java 的语法。然而,这当然不是使用该语言的最佳方式。Scala 是面向对象与函数式编程的混合体。要充分利用 Scala 的强大功能,需要重新思考框架的大多数 API。

我们将 Scala 支持作为单独模块的局限性很快显现出来。我们在 Play 1.x 中做出的初始设计选择,严重依赖 Java 反射 API 和字节码操作,使得在不彻底重新思考 Play 内部的一些基本部分的情况下,难以取得进展。与此同时,我们为 Scala 模块创建了几个很棒的组件,例如新的类型安全模板引擎和全新的 SQL 访问组件 Anorm。这就是为什么我们决定,为了充分发挥 Scala 在 Play 中的强大功能,我们将 Scala 支持从一个单独的模块迁移到 Play 2 的核心,Play 2 从一开始就被设计为原生支持 Scala 作为编程语言。

另一方面,Java 当然不会从 Play 2 中获得更少的支持;恰恰相反。Play 2 构建为我们提供了一个机会来增强 Java 开发人员的开发体验。Java 开发人员获得了真正的 Java API,该 API 是用所有 Java 特定性考虑编写的。

§强大的构建系统

从 Play 项目开始,我们就选择了一种新颖的方式来运行、编译和部署 Play 应用程序。它最初可能看起来像一个深奥的设计,但它对于提供异步 HTTP API(而不是标准 Servlet API)、通过实时编译和在开发过程中重新加载源代码来缩短反馈周期以及推广一种新的打包方法至关重要。因此,很难让 Play 遵循标准 JEE 约定。

如今,这种无容器部署的想法在 Java 世界中越来越被接受。这是一个设计选择,它允许 Play 框架在像 Heroku 这样的平台上原生运行,Heroku 引入了一种我们认为是 Java 应用程序在弹性 PaaS 平台上部署未来的模型。

然而,现有的 Java 构建系统不够灵活,无法支持这种新方法。由于我们希望提供直接的工具来运行和部署 Play 应用程序,因此在 Play 1.x 中,我们创建了一组 Python 脚本来处理构建和部署任务。

与此同时,使用 Play 进行更大型企业级项目的开发人员,这些项目需要构建过程定制和与现有公司构建系统集成,有点迷茫。我们与 Play 1.x 一起提供的 Python 脚本绝不是一个功能齐全的构建系统,而且不容易定制。这就是为什么我们决定为 Play 2 选择一个更强大的构建系统。

由于我们需要一个现代化的构建工具,它足够灵活,可以支持 Play 的原始约定,并且能够构建 Java 和 Scala 项目,因此我们选择在 Play 2 中集成 sbt。sbt 是 Scala 事实上的构建工具,并且在 Java 社区中也越来越受欢迎。

这也意味着更好地与 Maven 项目开箱即用集成,能够将您的项目打包并发布为一组简单的 JAR 文件到任何存储库,尤其是在开发时对任何依赖项目的实时编译和重新加载,即使对于标准的 Java 或 Scala 库项目也是如此。

§数据存储和模型集成

“数据存储”不再与“SQL 数据库”同义,也许从来都不是。许多有趣的数据存储模型正在流行起来,为不同的场景提供不同的属性。因此,对于像 Play 这样的 Web 框架来说,对开发人员将使用哪种数据存储做出大胆的假设变得很困难。Play 中的通用模型概念不再有意义,因为几乎不可能用单个 API 抽象所有这些类型的技术。

在 Play 2 中,我们希望让使用任何数据存储驱动程序、ORM 或任何其他数据库访问库变得非常容易,而无需与 Web 框架进行任何特殊集成。我们只想提供一组最小的帮助程序来处理常见的技术问题,例如管理连接边界。但是,我们也希望通过捆绑默认工具来访问经典数据库来维护 Play 框架的全栈方面,以供没有专门需求的用户使用,这就是 Play 2 具有 JPA、Slick 和 Anorm 等关系数据库访问库的原因。

下一步:Play 用户组


在本文档中发现错误?此页面的源代码可以在 此处 找到。在阅读了 文档指南 后,请随时贡献拉取请求。有疑问或建议要分享?前往 我们的社区论坛 与社区开始对话。