前言
晚上下班回家无聊看掘金Gayhub今日热门项目排行,突然瞄到一个有点意思关于微服务的项目。话说微服务框架在后端开发领域早已不是一个新的东西了,尤其是在框架这么多的Java平台,以spring boot为基础的构建的Spring cloud微服务框架基本已经成了不二选择。但是为啥我还会关注这个叫做英文名“Helidon”,中文名 “希利顿”的项目呢?还不是因为对微服务领域有着浓厚的兴趣(ps:很假吧,其实还是被oracle那略显土气红色logo吸引住了!)
框架特性
1.简单迅速
Helidon从设计的角度出发,高效易用,通过简单的Demo例子就能快速上手。由于Helidon它只是一个运行在高性能 Netty内核上的库的集合,所以它并没有其他过多的额外性能开销与设计上的臃肿。
2.支持MicroProfile
HelIdon支持 MicroProfile,并且提供了开发者熟悉的API,如JAX-RS、CDI和JSON-P/B。(ps:不熟悉也没啥关系),官方的MicroProfile实现了在自己的Helidon Reactive WebServer环境上快速运行。
3.Reactive WebServer (响应式web服务)
Helidon Reactive WebServer提供了一个运行在Netty内核上现代的函数式编程模型, HelIDon WebServer具有轻量级、灵活和响应式的提点,为当下流行的微服务提供了一个简单易用与快速构建的基础。如果熟悉的spring web flux 的话应该比较好理解这个了。
Helidon提供如下两种编程模式
- Helidon MP: MicroProfile 1.1 plus Health Check and Metrics
- Helidon SE: a small, functional style API
4.可观察性与服务弹性
Helidon提供服务健康检查、应用监控、链路追终与容错,可以通过接入Prometheus(监控)、 Zipkin(链路追踪) 、 Kubernetes来构建Helidon云应用。
快速入门
bb了那么久,不赶紧上手一波怎么行~
1.环境搭建 (Helidon SE)
1.1 创建一个 maven 工程,目录结构如下图:
1.2 在 pom.xml 文件中添加如下依赖:
这是直接采用官方提供的dependencyManagement配置,这样就不需要给每个Helidon组件提供具体的依赖版本了!!
<dependencies>
<!-- helidon webserver 依赖 -->
<dependency>
<groupId>io.helidon.webserver</groupId>
<artifactId>helidon-webserver-bundle</artifactId>
</dependency>
<!-- helidon 读取配置 少了这个依赖无法读取到yaml中的配置哦!!! -->
<dependency>
<groupId>io.helidon.config</groupId>
<artifactId>helidon-config-bundle</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.helidon</groupId>
<artifactId>helidon-bom</artifactId>
<version>0.9.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
复制代码
1.3 创建目录和配置文件:
在src/main/resources 目录下创建application.yaml,logging.properties文件:
- application.yaml : 用于配置项目运行所需的配置数据 (同spring boot一样,应用启动时会在类路径加载这个配置文件) 同样也支持application.conf、application.json、application.properties这几种格式。(不过还是建议使用yaml吧)
# web server 配置
server:
# 服务端口
port: 8080
# 服务主机
host: 0.0.0.0
# 自定义配置
app:
greeting: "Hello"
复制代码
具体配置可参考:官方配置指南
- logging.properties : 日志文件配置
# 控制台输出输出
handlers=java.util.logging.ConsoleHandler
# 定义全局日志级别,可以通过指定的handlers、loggers覆盖
.level=INFO
# Helidon Web Server has a custom log formatter that extends SimpleFormatter.
# It replaces "!thread!" with the current thread name
# Helidon Web Server 有一个自定义的格式化类 :io.helidon.webserver.netty.WebServerLogFormatter 用当前线程名正则表达式替换 “!thread!”
java.util.logging.ConsoleHandler.level=INFO
java.util.logging.ConsoleHandler.formatter=io.helidon.webserver.netty.WebServerLogFormatter
java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n
#组件定制日志级别
#io.helidon.webserver.level=INFO
#io.helidon.config.level=INFO
#io.helidon.security.level=INFO
#io.helidon.common.level=INFO
#io.netty.level=INFO
复制代码
1.4.1 创建启动类(其实就是一个主类main):
/**
* 防止实例化此类
*/
private Main() { }
/**
* 创建路由
*
* @return the new instance
*/
private static Routing createRouting() {
return Routing.builder()
//添加json返回支持
.register(JsonSupport.get())
.register("/greet", new GreetService())
.build();
}
public static void main(final String[] args) throws IOException {
// 加载日志配置
LogManager.getLogManager().readConfiguration(
Main.class.getResourceAsStream("/logging.properties"));
//默认会从类路径加载 application.yaml 配置文件
Config config = Config.create();
//获取application.yaml中 “server”部分webserver相关配置
ServerConfiguration serverConfig =
ServerConfiguration.fromConfig(config.get("server"));
//根据配置创建WebServer
WebServer server = WebServer.create(serverConfig, createRouting());
// Start the server and print some info.
// 开启服务时打印一些内容
server.start().thenAccept(ws -> System.out.println(
"WEB server is up! http://localhost:" + ws.port()));
// 服务停止时打印一些内容 ( 可以通过执行server.shutdown()关闭服务触发)
server.whenShutdown().thenRun(()
-> System.out.println("WEB server is DOWN. Good bye!"));
}
复制代码
1.4.2 创建服务类(相当于spring mvc的contoller):
public class GreetService implements Service {
/**
* 读取配置文件中的 “app”字段 部分配置
*/
private static final Config CONFIG = Config.create().get("app");
/**
* 读取配置文件中 “app”下层属性“greeting”字段属性值
*/
private static String greeting = CONFIG.get("greeting").asString("Hello xs");
/**
* 定义当前Service 路由规则
*/
@Override
public final void update(final Routing.Rules rules) {
rules
.get("/", this::getDefaultMessage)
.get("/{name}", this::getMessage)
.put("/greeting/{greeting}", this::updateGreeting);
}
/**
* 测试: http://localhost:8080/greet/ (get 请求)
*/
private void getDefaultMessage(final ServerRequest request, final ServerResponse response) {
String msg = String.format("%s %s!", greeting, "World");
JsonObject returnObject = Json.createObjectBuilder()
.add("message", msg)
.build();
response.send(returnObject);
}
/**
* 测试: http://localhost:8080/greet/xs (get 请求)
* 测试: http://localhost:8080/greet/xs?age=18 (get 请求)
*/
private void getMessage(final ServerRequest request, final ServerResponse response) {
//获取问号后面的查询参数
String age = request.queryParams().first("age").orElse("age 未提供!!!");
//获取路径参数
String name = request.path().param("name");
String msg = name+": "+age;
JsonObject returnObject = Json.createObjectBuilder()
.add("message", msg)
.build();
response.send(returnObject);
}
/**
* 测试: http://localhost:8080/greet/xs?age=18 (put 请求)
*/
private void updateGreeting(final ServerRequest request,final ServerResponse response) {
greeting = request.path().param("greeting");
JsonObject returnObject = Json.createObjectBuilder()
.add("greeting", greeting)
.build();
response.send(returnObject);
}
}
复制代码
Helidon SE Restful 服务开发流程
- 主类加载配置(日志配置、web server 配置)
- 定义路由规则(service级别路由,相当于spring mvc类级别的RequestMapping),同时添加JSON支持
- 实现Service接口“update”方法定义当前Service路由规则(相当于spring mvc 方法级别的RequestMapping)
- 通过ServerRequest获取请求,ServerResponse响应请求, 进行业务开发。
踩坑系列
- 建议使用官方提供的dependencyManagement管理Helidon模块版本,避免之间的依赖问题。
- 一定要添加“helidon-config-bundle”相关依赖,否则无法读取yaml配置
- http响应方法response.send()入参其实是有限制的,想要返回json数据必须使用“JsonObject”对象,这里不像spring mvc 默认提供了Jackson json转换器,是不会把pojo自动转换成json字符串的。不过这个send方法是可以传String类型的参数的,因此可以通过引入外部库转成json字符串输出吧。(目前还没看到其他有效手段,毕竟大部分人都不会使用javax中的json库吧)
总结
总体来讲Helidon SE开发还算是比较轻松的,跟spring boot + spring web flux 十分类似。需要有一定java 8基础,懂得函数式编程、链式调用上手更快。从几年前android平台带火的 RxJava,到spring 5 提供的webflux,无一不表明以函数式编程为核心,响应式开发大有不断上升的趋势。建议java平台的小伙伴们,多多用用java8 提供的Steam API 配合Lambda 表达式进行一些日常开发吧。毕竟不用多久java 11 就要出来了!