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

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

头图.png

作者 | 方剑(洛夜)  Spring Cloud Alibaba 开源项目负责人/创始人之一
来源|阿里巴巴云原生公众号

导读:本文摘自 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 正在成为主流,于是就诞生了下面这幅图,从单体应用的管理到微服务应用的管理再到函数的管理。

1.png

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

2.png

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

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

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

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

3.png

我们知道,因为 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
  • Consumer

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: 一次消息消费/生产/转换是一次函数调用。

4.png

这里再多介绍统一云厂商的 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:

@SpringBootApplication
public 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:

@SpringBootApplication
public 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-group

spring.cloud.stream.bindings.output.destination=output-topic

spring.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 与实战》一书正式开始预售啦,这是一本深入剖析 Spring Cloud 全家桶的书籍,涉及以下内容

  • Spring Boot 核心特性
  • Spring Cloud 服务注册/服务发现原理剖析
  • 双注册双订阅模型完成 Eureka 迁移至 Nacos 的案例
  • 负载均衡:Spring Cloud LoadBalancer 和 Netflix Ribbon
  • Dubbo Spring Cloud:Spring Cloud 与 Apache Dubbo 的融合
  • Spring Cloud 灰度发布案例
  • Spring 体系配置,动态刷新加载原理剖析
  • Spring Cloud Circuit Breaker 抽象以及 Sentinel、Hystrix、Resilience4j 熔断器对比
  • Spring 体系消息编程模型剖析
  • Spring Cloud Data Flow 完成批处理和流处理任务
  • Spring Cloud Gateway 网关剖析
  • Spring 与 Serverless 的融合

点击了解详情,更有机会赢取免费图书

作者简介

方剑  Spring Cloud Alibaba 开源项目负责人/创始人之一。《深入理解 Spring Cloud 与实战》作者,Apache RocketMQ Committer,Alibaba Nacos Committer。曾在个人博客上编写过《SpringMVC 源码分析系列》、《SpringBoot 源码分析系列》文章,目前,关注微服务、云原生、Kubernetes。

5.png

《深入理解 Spring Cloud 与实战》作者方剑将出席 1 月 9 日 Spring Cloud Alibaba 上海站,现场活动也有互动赠书活动,欢迎来现场与作者面基。

点击链接参与活动报名:https://www.huodongxing.com/event/2576519081911

相关实践学习
【AI破次元壁合照】少年白马醉春风,函数计算一键部署AI绘画平台
本次实验基于阿里云函数计算产品能力开发AI绘画平台,可让您实现“破次元壁”与角色合照,为角色换背景效果,用AI绘图技术绘出属于自己的少年江湖。
从 0 入门函数计算
在函数计算的架构中,开发者只需要编写业务代码,并监控业务运行情况就可以了。这将开发者从繁重的运维工作中解放出来,将精力投入到更有意义的开发任务上。
相关文章
|
5月前
|
安全 Java API
Java Web 在线商城项目最新技术实操指南帮助开发者高效完成商城项目开发
本项目基于Spring Boot 3.2与Vue 3构建现代化在线商城,涵盖技术选型、核心功能实现、安全控制与容器化部署,助开发者掌握最新Java Web全栈开发实践。
546 1
|
5月前
|
人工智能 Java 开发者
阿里出手!Java 开发者狂喜!开源 AI Agent 框架 JManus 来了,初次见面就心动~
JManus是阿里开源的Java版OpenManus,基于Spring AI Alibaba框架,助力Java开发者便捷应用AI技术。支持多Agent框架、网页配置、MCP协议及PLAN-ACT模式,可集成多模型,适配阿里云百炼平台与本地ollama。提供Docker与源码部署方式,具备无限上下文处理能力,适用于复杂AI场景。当前仍在完善模型配置等功能,欢迎参与开源共建。
2289 58
阿里出手!Java 开发者狂喜!开源 AI Agent 框架 JManus 来了,初次见面就心动~
|
5月前
|
缓存 Java 开发者
Java 开发者必看!ArrayList 和 LinkedList 的性能厮杀:选错一次,代码慢成蜗牛
本文深入解析了 Java 中 ArrayList 和 LinkedList 的性能差异,揭示了它们在不同操作下的表现。通过对比随机访问、插入、删除等操作的效率,指出 ArrayList 在多数场景下更高效,而 LinkedList 仅在特定情况下表现优异。文章强调选择合适容器对程序性能的重要性,并提供了实用的选择法则。
289 3
|
6月前
|
Java 测试技术 API
2025 年 Java 开发者必知的最新技术实操指南全览
本指南涵盖Java 21+核心实操,详解虚拟线程、Spring Boot 3.3+GraalVM、Jakarta EE 10+MicroProfile 6微服务开发,并提供现代Java开发最佳实践,助力开发者高效构建高性能应用。
939 4
|
8月前
|
SQL 人工智能 Java
阿里云百炼开源面向 Java 开发者的 NL2SQL 智能体框架
Spring-ai-alibaba-nl2sql 是析言 GBI 产品在数据问答领域的一次重要开源尝试,专注于 NL2SQL 场景下的核心能力开放。
2329 48
|
6月前
|
人工智能 自然语言处理 Java
面向 Java 开发者:2024 最新技术栈下 Java 与 AI/ML 融合的实操详尽指南
Java与AI/ML融合实践指南:2024技术栈实战 本文提供了Java与AI/ML融合的实操指南,基于2024年最新技术栈(Java 21、DJL 0.27.0、Spring Boot 3.2等)。主要内容包括: 环境配置:详细说明Java 21、Maven依赖和核心技术组件的安装步骤 图像分类服务:通过Spring Boot集成ResNet-50模型,实现REST接口图像分类功能 智能问答系统:展示基于RAG架构的文档处理与向量检索实现 性能优化:利用虚拟线程、GraalVM等新技术提升AI服务性能 文
655 0
|
SQL Java 数据库连接
为何JDBC是Java开发者的“心头好”?原因竟然这么简单!
为何JDBC是Java开发者的“心头好”?原因竟然这么简单!
137 3
|
安全 Java API
告别繁琐编码,拥抱Java 8新特性:Stream API与Optional类助你高效编程,成就卓越开发者!
【8月更文挑战第29天】Java 8为开发者引入了多项新特性,其中Stream API和Optional类尤其值得关注。Stream API对集合操作进行了高级抽象,支持声明式的数据处理,避免了显式循环代码的编写;而Optional类则作为非空值的容器,有效减少了空指针异常的风险。通过几个实战示例,我们展示了如何利用Stream API进行过滤与转换操作,以及如何借助Optional类安全地处理可能为null的数据,从而使代码更加简洁和健壮。
457 0

相关产品

  • 函数计算