Google Cloud 通用数据库构建4 – Kubernetes & SpringBoot & Apache Camel第1部分
我们团队正在设计采用微服务架构的下一代后端,在全公共云上。
情况
上次我创建了一个SpringBoot应用程序并将其打包为Docker镜像,然后在GKE上进行了部署。但为了实现持久化存储,我需要创建一个Web服务。虽然我认为可以使用任何工具来创建该服务,但个人而言,我很喜欢Apache Camel。
在日本,它似乎没有太普及,但它是EIP的实现,可以通过重用各种组件来构建服务。它的代码量非常少。这次我不打算深入研究Camel,而是着重集成到SpringBoot应用程序中。
pom.xml -> 自行内容修改
将所需的库导入pom.xml文件。由于进行了完整可执行JAR打包,所以这些库都包含在一个JAR文件中。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>jp.co.yahoo.zeolite.agent</groupId>
<artifactId>storeagent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>storeagent</name>
<description>Spring Boot Application</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<camel-ver>2.17.1</camel-ver>
</properties>
<dependencies>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Apache Camel -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>${camel-ver}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-restlet</artifactId>
<version>${camel-ver}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-boot</artifactId>
<version>${camel-ver}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-swagger-java</artifactId>
<version>${camel-ver}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.3.6.RELEASE</version>
<configuration>
<mainClass>jp.co.yahoo.zeolite.agent.StoreagentApplication</mainClass>
<layout>WAR</layout>
<executable>true</executable>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
主要添加的库如下。
-
- spring-boot-starter-jetty
組み込みtomcat→組み込みjettyにコンテナを切り替え。
spring-boot-starter-thymeleaf
可視化のためのtoolも作ろうと思うので、テンプレートエンジンにthymeleaf(タイムリーフ)
camel-core
Apache Camelのコアライブラリ
camel-restlet
restAPI作成に使用します。他にいくつかCamelコンポーネントがあるが、今回はこれを使用。
camel-swagger-java
api-docを作ってくれるのが嬉しい。
API Gatewayや、Apigeeとつなぐ際にも便利。今後はこれがrest定義のスタンダードになりそうですね。
camel-spring-boot
Apache CamelのSpringBootサポート
路線的定義
正如前面所述,Apache Camel将各个Camel组件组合起来构建应用程序。这些组件主要集中在官方网站上。通过重写RouteBuilder类的configure方法,我们可以按照下面的方式实现称为Camel Route的流程。
from("jetty:https://0.0.0.0/myapp/").to("bean:myBean?method=methodName");
例如,在这种情况下,可以启动一个可以通过localhost:80/myapp访问的webservice(本质上只是启动了一个嵌入式jetty)。
头部信息和正文信息将绑定到消息中,并几乎原封不动地传递给通过to()方法调用的组件。(在这种情况下,使用了bean组件,因此将传递给在上下文中注册的myBean实例的methodName方法)
本次使用camel-spring-boot来实现,提供了一个继承自RouteBuilder类的FatJarRouter类。
只需要一种选项。将Spring Boot应用程序的启动类继承FatJarRouter类即可。
@SpringBootApplication
@ComponentScan("jp.co.yahoo.zeolite")
public class StoreagentApplication extends FatJarRouter {
public static void main(String[] args) {
SpringApplication.run(StoreagentApplication.class, args);
}
@Override
public void configure() throws Exception {
//handling Exceptions.
onException(Exception.class)
.handled(true)
.setBody(exceptionMessage().prepend("{\"error\":\"").append("\"}"))
.convertBodyTo(String.class)
.log(LoggingLevel.ERROR, "${body}")
.to("direct:setWebserviceResponseHeaders")
.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(500));
errorHandler(deadLetterChannel("direct:deadlog").maximumRedeliveries(0));
from("direct:deadlog").routeId("DEAD_LOG").log(LoggingLevel.ERROR, "${body}");
from("direct:setWebserviceResponseHeaders")
.routeId("SET_WEB_HEADERS")
.setHeader(Exchange.CONTENT_TYPE,
constant("application/json; charset=utf-8"));
//Rest Configurations.
restConfiguration().component("restlet")
.enableCORS(true)
.apiContextPath("/api-docs")
.apiProperty("api.title", "Zeolite StoreAgent APIs")
.apiProperty("api.version", "1.0.0")
.apiProperty("cors", "true")
.contextPath("/service").host(InetAddress.getLocalHost().getHostName()).port(21001)
.dataFormatProperty("prettyPrint", "true")
.bindingMode(RestBindingMode.off)
.componentProperty("disableStreamCache", "true");
//Rest API
rest("/upsert")
.description("Upsert API. 対象ItemをUpsertします。")
.produces("application/json").consumes("application/json")
.post().description("upsert the item.")
.param().name("itemKey").type(RestParamType.header).description("The key of an item.").dataType("string").endParam()
.param().name("item").type(RestParamType.body).description("The item to store.").dataType("string").endParam()
.responseMessage().header("http Status code").endResponseHeader().endResponseMessage()
.to("direct:upsert");
from("direct:upsert")
.setBody(constant("{\"message\" : \"OK!\"}"))
.to("mock:upsert");
}
}
由于本次还使用了camel-swagger,因此在规范文档中一并写入所需的注释,具体如下所示。
//Rest API
rest("/upsert")
.description("Upsert API. 対象ItemをUpsertします。")
.produces("application/json").consumes("application/json")
.post().description("upsert the item.")
.param().name("itemKey").type(RestParamType.header).description("The key of an item.").dataType("string").endParam()
.param().name("item").type(RestParamType.body).description("The item to store.").dataType("string").endParam()
.responseMessage().header("http Status code").endResponseHeader().endResponseMessage()
.to("direct:upsert");
只需通过Maven启动即可。尝试使用Postman发送请求。
正常地回来了。
另外,还可以尝试使用Camel Swagger。
有关Swagger的信息,请参考下面的内容。
-
- swagger
- camel-swagger
在默认情况下,camel-swagger会在/api-docs上创建定义文件。
在这种情况下,访问http://localhost:21001/service/api-docs,将返回定义文档。
将其提供给SwaggerUI或连接的APIGateway等,非常方便。
一种感觉
只需要这么少的代码,就可以启动带有定义文档的REST API。而且HTTP的header和body会直接绑定到Message的header和body,非常方便。
最令人高兴的是可以重复使用有成就的事物。
以前,我们自己创建了一个叫做CamelBoot的类,用FullExecutable来实现机动性,但随着SpringBoot的推出,这一切都变得不再需要了。只需要一个jar文件进行启动,无需任何启动脚本。只需放置并运行即可。因此,它与Docker也非常兼容。无论是在Mac还是在Windows上进行开发,都可以通过IDE进行开发,并通过maven直接启动和调试。
在我心中,它已经成为了一种稳定的架构。
如果了解这些,它将成为在紧急情况下拯救项目的强大武器。
我已经多次得到救助。
基本上,无论遇到何种情况,我都能够在短时间内通过使用SpringBoot+ApacheCamel+Thymeleaf+Commons等工具来解决。
因为是POJO,所以更容易外包。
为什么不流行一些呢…
下次
要不要深入探讨一下上述内容呢?