本文摘自 Spring Cloud Alibaba 开源项目创始团队成员方剑撰写的 《深入理解 Spring Cloud 与实战》 一书,主要讲述了 Java 微服务框架 Spring Boot/Cloud 这个事实标准下如何应对 FaaS 场景。

Serverless & FaaS

2019 年,O'Reilly 对 1500 名 IT 专业人员的调查中,有 40% 的受访者在采用 Serverless 架构的组织中工作。2020 年DataDog 调查显示,现在有超过 50% 的 AWS 用户正在使用 Serverless 架构的 AWS Lambda。

Serverless 正在成为主流,于是就诞生了下面这幅图,从单体应用的管理到微服务应用的管理再到函数的管理。

Serverless 到目前为止还没有一个精准定义。Martin Fowler 在个人博客上有一篇《Serverless Architectures》文章,其对 Serverless 的的定义分成了 BaaS 或 FaaS 。

Baas 是全称是 Backend-as-a-Service,后端即服务,FaaS 的全称是 Function-as-a-Service,函数即服务。

今天我们来聊聊 FaaS。这是维基百科对 FaaS 的定义:

函数即服务(FaaS)是一类云计算服务,它提供了一个平台,使客户可以开发,运行和管理应用程序功能,而无需构建和维护通常与开发和启动应用程序相关的基础架构。遵循此模型构建应用程序是实现 Serverless 架构的一种方法,通常在构建微服务应用程序时使用。

对于 Python、JavaScript 这种天生支持 Lambda 的开发语言,和 FaaS 简直是完美结合。Serverless Framework 的调研报告也很好地说明了这一点。NodeJS、Python 是 FaaS 使用率前二的语言。

我们知道,因为 JVM 占用的内存比较大,所以 Java 应用的启动会有点慢,不太适合 FaaS 这个场景,这也是 Java 在使用率上偏低的原因。

另外,对 Java 开发者来说 Spring Boot/Cloud 已经成为了事实标准,依赖注入是 Spring Framework 的核心,Spring Boot/Cloud 这个事实标准应对 FaaS 这个场景,会碰撞出怎么样的火花呢?这就是今天我们要聊的 Spring Cloud Function。

Java Function

在对 Spring Cloud Function 介绍之前,我们先来看 Java 里的核心函数定义。

JDK 1.8 推出了新特性 Lambda 表达式,java.util.function 包下面提供了很多的函数。这 3 个函数尤为重要:

1. java.util.function.Function: 需要一个参数,得到另一个结果。

@FunctionalInterface
public interface Function<T, R> {   R apply(T t);
}

比如通过 Stream API 里的 map 方法可以通过 Function 把字符串从小写变成大写:

Stream.of("a", "b", "c").map(String::toUpperCase);

这里的 map 方法需要一个 Function 参数:

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

2. java.util.function.Consumer: 需要一个参数进行操作,无返回值。

@FunctionalInterface
public interface Consumer<T> {    void accept(T t);
}

比如通过 Stream API 里的 forEach 方法遍历每个元素,做对应的业务逻辑处理:

RestTemplate restTemplate = new RestTemplate();
Stream.of("200", "201", "202").forEach(code -> {ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://httpbin.org/status/" + code, String.class);    System.out.println(responseEntity.getStatusCode());
});

3. java.util.function.Supplier: 得到一个结果,无输入参数。

@FunctionalInterface
public interface Supplier<T> { T get();
}

比如自定义 Supplier 可以返回随机数:

Random random = new Random();Supplier supplier100 = () -> random.nextInt(100);
Supplier supplier1000 = () -> random.nextInt(1000);System.out.println(supplier100.get());
System.out.println(supplier1000.get());

Spring Cloud Function

Java Function 的编程模型非常简单,本质上就是这 3 个核心函数:

  • Supplier

  • Function<I, O>

  • Consumer<I>

Spring Cloud Function 是 Spring 生态跟 Serverless(FaaS) 相关的一个项目。它出现的目的是增强 Java Function,主要体现在这几点:

  • 统一云厂商的 FaaS 编程模型: Spring Cloud Function 的口号是 "Write Once, Run Anywhere"。我们写的 Spring Cloud Function 代码可以运行在本地、各个云厂商(AWS Lambda, GCP Cloud Functions, Azure Functions)。

  • 自动类型转换: 理解过 Spring MVC 或者 Spring Cloud Stream 的同学肯定对 HttpMessageConverter 或者 MessageConverter 模型,这个转换器的作用是将 HTTP BODY(或者 Message Payload)、HTTP Query Parameter、HTTP HEADER(或者 Message Header)自动转换成对应的 POJO。有了这个特性后,我们就无需关注函数的入参和返回值,用 String 参数就可以获取原始的入参信息,用 User 这个 POJO 参数就可以将原始的入参参数自动转换成 User 对象。

  • 函数组合: 可以让多个函数之间进行组合操作。

  • 函数管理: 新增 FunctionCatalog、FunctionRegistry 接口用于 Function 的管理。管理 ApplicationContext 内的 Function,动态注册 Function 等操作。

  • Reactive 支持: Spring Cloud Function 新增比如 FluxFunction、FluxSupplier、FunctionConsumer 这种 Reactive 函数。

  • 自动跟 Spring 生态内部原有的组件进行深度集成:

    • Spring Web/Spring WebFlux: 一次 HTTP 请求是一次函数调用。

    • Spring Cloud Task: 一次任务执行是一次函数调用。

    • Spring Cloud Stream: 一次消息消费/生产/转换是一次函数调用。

这里再多介绍统一云厂商的 FaaS 编程模型,让大家对 Spring Cloud Function 更有体感。

AWS Lambda 是第一个是提供 FaaS 服务的云厂商,RequestStreamHandler 是 AWS 提供的针对 Java 开发者的接口,需要实现这个接口:

public class HandlerStream implements RequestStreamHandler {  @Override  public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException{    ...

Azure Functions 针对 Java 开发者提供了 @HttpTrigger 注解:

public class Function {    public String echo(@HttpTrigger(name = "req",       methods = {HttpMethod.POST},  authLevel = AuthorizationLevel.ANONYMOUS)         String req, ExecutionContext context) { ...    }
}

从这两段代码可以看出,不同的云厂商要编写不同的代码。如果要变换云厂商,这个过程会很痛苦。

另外,无论是 AWS、Azure 或者 GCP 提供的接口或注解,他们没有任何 Spring 上下文相关的初始化逻辑。如果我们是一个 Spring Boot/Cloud 应用迁移到 FaaS 平台,需要添加 Spring 上下文初始化逻辑等改动量。

Spring Cloud Function 的出现就是为了解决这些问题。

Spring Cloud Function 的使用

Spring Cloud Function & Spring Web:

@SpringBootApplicationpublic class SpringCloudFunctionWebApplication {public static void main(String[] args) {SpringApplication.run(SpringCloudFunctionWebApplication.class, args);    }@Bean    public Function<String, String> upperCase() { return s -> s.toUpperCase();    }@Bean    public Function<User, String> user() {return user -> user.toString();    }
}

访问对应的 Endpoint:

$ curl -XPOST -H "Content-Type: text/plain" localhost:8080/upperCase -d hello
HELLO
$ curl -XPOST -H "Content-Type: text/plain" localhost:8080/user -d '{"name":"hello SCF"}'
User{name\u003d\u0027hello SCF\u0027}

Spring Cloud Function & Spring Cloud Stream:

@SpringBootApplicationpublic class SpringCloudFunctionStreamApplication {public static void main(String[] args) {SpringApplication.run(SpringCloudFunctionStreamApplication.class, args);   }@Bean    public Function<String, String> uppercase() {return x -> x.toUpperCase();  }@Bean   public Function<String, String> prefix() {  return x -> "prefix-" + x;   }
}

加上 function 相关的配置(针对 input-topic 上的每个消息,payload 转换大写后再加上 prefix- 前缀,再写到 output-topic 上):

spring.cloud.stream.bindings.input.destination=input-topic
spring.cloud.stream.bindings.input.group=scf-groupspring.cloud.stream.bindings.output.destination=output-topicspring.cloud.stream.function.definition=uppercase|prefix

Spring Cloud Function & Spring Cloud Task:

@SpringBootApplication
public class SpringCloudFunctionTaskApplication {public static void main(String[] args) { SpringApplication.run(SpringCloudFunctionTaskApplication.class, args);    }@Bean   public Supplier<List<String>> supplier() {  return () -> Arrays.asList("200", "201", "202");    }@Bean   public Function<List<String>, List<String>> function() {return (list) ->   list.stream().map( item -> "prefix-" + item).collect(Collectors.toList());    }@Bean   public Consumer<List<String>> consumer() { return (list) -> {        list.stream().forEach(System.out::println); };   }
}

加上 function 相关的配置(Supplier 模拟任务的输入源,Function 模拟对任务输入源的处理,Consumer 模拟处理对 Function 处理输入源后的数据):

spring.cloud.function.task.function=function
spring.cloud.function.task.supplier=supplier
spring.cloud.function.task.consumer=consumer

(完)

作者简介

方剑,花名洛夜,Spring Cloud Alibaba 开源项目负责人/创始人之一。Apache RocketMQ Committer,Alibaba Nacos Committer。目前就职于阿里巴巴集团。

曾在个人博客上编写过《Spring MVC源码分析系列》、《Spring Boot源码分析系列》文章。目前,关注微服务、云原生、Kubernetes。

图书推荐

▊《深入理解Spring Cloud与实战》

方剑 编著

  • Spring Cloud Alibaba创始人倾力打造

  • 理论与实践相结合,核心知识点辅以案例讲解

这是一本深入剖析 Spring Cloud 全家桶的书籍,主要介绍Spring Cloud各个核心组件的设计原理,以及目前流行的Spring Cloud Alibaba和 Netflix组件,并且剖析Spring Cloud对流处理、批处理,以及目前业界流行的Serverless的支持。在介绍各部分内容时,本书将理论与实践相结合,对每个核心知识点都给出了具体的案例应用,以帮助读者掌握核心组件的设计理念。

抽奖赠书

截止时间:2021年2月1日 17:00

如何抽奖:扫描下方二维码,关注公众号,回复关键词 :20210127

下次你更希望我们送哪本书呢?

留言告诉我们!

距离 Java 开发者玩转 Serverless,到底还有多远?相关推荐

  1. 云原生开发者训练营启动!3天教会你玩转Serverless

    立即报名:https://developer.aliyun.com/learning/trainingcamp/serverless/1?accounttraceid=cb96a7edbf404ca9 ...

  2. java 搭建企业应用框架_溯源微服务开发体系:一位Java开发者的转型思考

    作者丨赵钰莹 简单来说,微服务是将大型单体应用程序和服务拆分为数个甚至数十个微服务,可扩展单个组件而不是整个应用程序堆栈,从而满足服务等级协议.然而,这个过程涉及很多问题需要解决,比如拆分原则.容量规 ...

  3. Java 开发者每天都在做什么?

    作为一名 在大.中.小微企业都待过 的 Java 开发者,今天和大家分享下自己在不同公司的工作日常和收获.包括一些个人积累的工作提升经验,以及一些 Java 学习的方法和资源. 先从我的第一份 Jav ...

  4. Java开发者薪资最低?程序员只能干到30岁?国外真的没有996?Intellij真的比Eclipse受欢迎?

    Stack Overflow作为全球最大的程序设计领域的问答网站,每年都会出据一份开发者调查报告.近日,Stack Overflow公布了其第9次年度开发者调查报告(https://insights. ...

  5. 2021 年 Java 开发者生产力报告

    责编 | 丁恩华 出品 | CSDN(ID:CSDNnews) 新的 2021 年,Perforce 公司依然没有 "爽约".前不久,这家公司发布了其第九份年度全球 Java 开发 ...

  6. Java 开发者希望未来使用 Python 和 Go

    作者 | 段段段落 本文经授权转载自开源中国(ID:oschina2013) 去年秋天,JetBrains 对超过 1500 名 Java 开发者的学习模式和偏好进行了调查.不妨看看公布的调查报告中一 ...

  7. 调查 10,500 名 Java 开发者发现,收费的 OracleJDK 仍是主流、IntelliJ IDEA 最受欢迎...

    昨日,作为"第一家"公开宣布将裁员 15% 的滴滴,一时之间被大众推向了舆论的风口浪尖,但与此同时,因为其不变相且透明的裁员举措也为自己赢得了一片叫好声.然不可否认的是,从此事件乃 ...

  8. 真相:Java 开发者钟爱 Kotlin 的五个原因

    [CSDN编者按]现在Kotlin语言越来越流行.它不仅广泛用在移动应用开发上,也能用于服务器端系统上.你也许知道,Kotlin是个运行在JVM上的静态类型编程语言. Kotlin之所以流行的主要原因 ...

  9. 【Java开发者专场】阿里专家梁笑:2018双十一下单成功率99.9%!供应链服务平台如何迎接大促...

    本篇文章来自于2018年12月22日举办的<阿里云栖开发者沙龙-Java技术专场>,梁笑专家是该专场第一位演讲的嘉宾,本篇文章是根据梁笑专家在<阿里云栖开发者沙龙-Java技术专场& ...

最新文章

  1. SAP WM高阶之上架策略B (Bulk Storage)
  2. numpy学习2:数组创建方式
  3. Android图片转换类 1. Bitmap去色,转换为黑白的灰度图, 2. Bitmap图片加圆角效果
  4. 【MySQL】MySQL 两种排序算法
  5. 从 Microsoft Dynamics CRM 4.0 server迁移到 Microsoft Dynamics CRM 2013 Server
  6. 基于modbus协议的工业自动化网络规范_一种基于Modbus的工业通信网关设计
  7. kubernetes endpoints是什么
  8. 项目总结 -谷粒学院
  9. aucc2018插件_Voxengo音频插件合集2018最新版
  10. 基本磁盘转换动态磁盘,再转换为基本磁盘,分区数据丢失
  11. 链桨PaddleDTX系列 - xdb源码分析(一)
  12. 云计算需要学什么?学习云计算能从事什么岗位?
  13. Docker技术之容器与外部相连
  14. Uni-app 实现离线打包 安卓篇
  15. matlab算非齐次方程,matlab-线性代数 非齐次方程组 判断是否有唯一解
  16. flex布局对行内子元素的影响
  17. 利用python和Sen2cor对Sentinel2进行批量大气校正
  18. 认证管理(锐捷网关篇)
  19. 接口隔离原则:接口里的方法,你都用得到吗?
  20. 联发科MT6580_datasheet/规格书资料分享

热门文章

  1. MySQL 复制滞后怎么办?其实方法很简单
  2. linux find命令 报错 遗漏"-exec"的参数 解决方法
  3. golang map 排序
  4. mysql表结构 转 golang 结构体struct
  5. python3 str() repr() 区别
  6. python3 list 列表 方法说明
  7. 《0day安全:软件漏洞分析技术》的一点总结
  8. 迭代器报“vector iterators incompatible”错的几种可能
  9. java设计模式---命令模式
  10. Cygwin获取root权限