在微服务天堂中Ratpack和Spring Boot是天造地设的一对。它们都是以开发者为中心的运行于JVM之上的web框架,侧重于生产率、效率以及轻量级部署。他们在服务程序的开发中带来了各自的好处。Ratpack通过一个高吞吐量、非阻塞式的web层提供了一个反应式编程模型,而且对应用程序结构的定义和HTTP请求过程提供了一个便利的处理程序链;Spring Boot集成了整个Spring生态系统,为应用程序提供了一种简单的方式来配置和启用组件。Ratpack和Spring Boot是构建原生支持计算云的基于数据驱动的微服务的不二选择。
\\Ratpack并不关心应用程序底层使用了什么样的依赖注入框架。相反,应用程序可以通过Ratpack提供的DI抽象(被称为Registry)访问服务层组件。Ratpack的Registry是构成其基础设施的一部分,其提供了一个接口,DI提供者可以使用注册器回调(registry backing)机制来参与到组件解决方案序列中。
\\Ratpack直接为Guice和Spring Boot提供了注册器回调机制,开发人员可以为应用程序灵活选择使用的依赖注入框架。
\\在本文中我们将演示使用Ratpack和Spring Boot构建一个RESTful风格的基于数据驱动的微服务,背后使用了Spring Data用于操作数据。
\\开始构建Ratpack项目的最佳方式是创建Gradle脚本以及标准的Java项目结构。Gradle是Ratpack原生支持的构建系统,其实由于Ratpack只是一组简单的JVM库,所以其实它适用于任何构建系统(不管你的需求有多特别)。如果你还未安装Gradle,那么安装它最佳方式是通过Groovy enVironment Manager工具。示例项目的构建脚本如列表1所示。
\\列表1
\\\\buildscript {\ repositories {\ jcenter()\ }\ dependencies {\ classpath 'io.ratpack:ratpack-gradle:0.9.18'\ }\}\\apply plugin: 'io.ratpack.ratpack-java'\apply plugin: 'idea'\apply plugin: 'eclipse'\\repositories {\ jcenter()\}\\dependencies {\ compile ratpack.dependency('spring-boot') (1)\}\\mainClassName = \"springpack.Main\" (2)\\eclipse {\ classpath {\ containers.remove('org.eclipse.jdt.launching.JRE_CONTAINER')\ containers 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8'\ }\}
\\
在(1)部分中,构建脚本通过调用Ratpack Gradle插件的ratpack.dependency(..)方法引入了Ratpack和Spring Boot的集成。根据构建脚本和当前项目结构,我们可以创建一个“主类”(main class),其作为可运行的类来启动和运行应用程序。注意(2)中我们指定了主类的名称,所以使用命令行工具时会更简练。这意味着实际的主类名必须与之一致,所以需要在本项目的src/main/java目录中创建一个名为springpack.Main的类。
\\在主类中,我们通过工厂方法构造了RatpackServer的一个实例,在start方法中提供了对应用程序的定义。该定义中我们编写了RESTful API处理器链。请参见列表2中对Main类的演示。注意Ratpack要求的编译环境为Java 8。
\\列表2
\\\\package springpack;\\import ratpack.server.RatpackServer;\\public class Main {\\ public static void main(String[] args) throws Exception {\ RatpackServer.start(spec -\u0026gt; spec\ .handlers(chain -\u0026gt; chain (1)\ .prefix(\"api\", pchain -\u0026gt; pchain (2)\ .all(ctx -\u0026gt; ctx (3)\ .byMethod(method -\u0026gt; method (4)\ .get(() -\u0026gt; ctx.render(\"Received GET request\"))\ .post(() -\u0026gt; ctx.render(\"Received POST request\"))\ .put(() -\u0026gt; ctx.render(\"Received PUT request\"))\ .delete(() -\u0026gt; ctx.render(\"Received DELETE request\"))\ )\ )\ )\ )\ );\ }\}\
\\
如果我们仔细剖析主类中的应用程序定义,我们可以识别出一些关键知识点,对于不熟悉Ratpack的人来说,我们需要对这些知识点做进一步解释。第一个值得注意的点在(1)中处理器区域定义了一个处理器链,该处理器链用于处理Ratpack流中的HTTP请求。通过链式定义的处理器描述了它们能够处理的请求类型。特别在(2)中我们定义了一个前缀处理器类型,指定它被绑定到“api”这个HTTP路由。前缀处理器创建了一个新的处理器链,用来处理匹配”/api” 端口(endpoint)到来的请求。在(3)处我们使用了所有的处理器类型来指定所有到来的请求应该运行在我们提供的处理器中,在(4)处我们使用Ratpack的byMethod机制来将get,post,put和delete处理器绑定到到各自的HTTP方法中。
\\在项目根目录下,我们可以通过命令行简单使用gradle的“run”命令运行该应用程序。这会启动web服务器并绑定到端口5050。为了演示当前项目的功能,确保处理器结构工作正常,我们可以在命令行中通过curl运行一些测试:
\\可以看到,应用程序处理器链可以正确地路由请求,我们建立了RESTful API的结构。接下来需要改善这些API…
\\为了演示的缘故,让我们尽量保持简单,改造该微服务以便可以对一个User领域对象进行CRUD操作。通过REST接口,客户可以做以下事情:
\\在之前小节中我们定义的处理器已经包含了大多数处理这种需求的基础设施。但根据需求我们还需要做细微调整。例如,我们现在需要绑定处理器接收用户名作为路径变量。列表3中是更新后的代码,主类中的处理器可以满足现在的需求。
\\列表3
\\\\package springpack;\\import ratpack.server.RatpackServer;\\public class Main {\\ public static void main(String[] args) throws Exception {\ RatpackServer.start(spec -\u0026gt; spec\ .handlers(chain -\u0026gt; chain\ .prefix(\"api/users\", pchain -\u0026gt; pchain (1)\ .prefix(\":username\", uchain -\u0026gt; uchain (2)\ .all(ctx -\u0026gt; { (3)\ String username = ctx.getPathTokens().get(\"username\");\ ctx.byMethod(method -\u0026gt; method (4)\ .get(() -\u0026gt; ctx.render(\"Received request for user: \" + username))\ .put(() -\u0026gt; {\ String json = ctx.getRequest().getBody().getText();\ ctx.render(\"Received update request for user: \" + username + \