Go,Go,GraalVM 与 Spring Native:我在 Native Image-ville 的冒险

工程 | Josh Long | 2021 年 12 月 29 日 | ...

嗨,Spring 粉丝们!新年快乐!我不敢相信我们这么快就走到这一步了,但我们确实做到了。去年非常忙碌,而我最喜欢的事情之一就是利用 Spring Native 构建基于 GraalVM 的特定于体系结构的原生镜像的机会。

我们发布了 Spring Native 0.11,这很棒,因为它具有一个全新的 AOT(提前)引擎,彻底改变了我们将 Spring Boot 应用程序转换为 GraalVM 原生镜像的方式。在过去的两年里,我一直都在使用 GraalVM,而这个新版本是 Spring Native 故事中一个巨大的、革命性的进步,也是迈向 Spring Framework 6 和 Spring Boot 3 的旅程中的巨大飞跃,这两者都将在 2022 年发布。

上个月我也一直在尝试这个新版本。Spring Native 适用于 Spring 本身支持的大量用例,因此,对于大多数应用程序来说,我发现无需任何更改即可正常工作。也就是说,有些东西在 Spring Native 上下文或任何 GraalVM 上下文中都需要一些帮助才能工作。例如,如果您告诉 GraalVM 您正在做的事情可能会让它感到困惑 - 代理、序列化、资源加载等,这将有所帮助。Spring Native 提供了一种机制 - *提示* - 您可以通过这种机制来做到这一点。这很容易。但仍然必须这样做。因此,我一直在访问一些我认为可能需要一些帮助的项目,并试图使它们正常工作。

MyBatis 和 Spring Native

我让 Spring 和 MyBatis 很好地工作,并将它们放在一个示例分支中。 请参阅此博客以了解更多信息。让 Spring 和 MyBatis Spring Boot 自动配置工作起来很有挑战性。我开始一点一点地重建自动配置,并设法构建了一个无可辩驳地不太有用、不太健壮的 适用于 MyBatis 的 Spring Boot 自动配置,它也适用于 Spring Native。希望我们能够以此为基础,找出如何弥合差距并使提供的、受支持的自动配置也能正常工作。我已经与 MyBatis 团队的一些人讨论了可能包含其中一些工作的内容。(拭目以待!)。使用此概念验证的 Spring Boot 自动配置和 Spring Native 配置,您可以创建如下所示的 MyBatis SQL Mapper


@Mapper
public interface CityMapper {

	@Insert("INSERT INTO city (name, state, country) VALUES(#{name}, #{state}, #{country})")
	@Options(useGeneratedKeys = true, keyProperty = "id")
	void insert(City city);

	@Select("SELECT id, name, state, country FROM city ")
	Collection<City> findAll();
}

Spring Retrosocket 和 Spring Native

我还更新了 Spring Retrosocket 项目以与 Spring Native 一起使用。Spring Retrosocket 是一个声明式的 FeignRetrofit 类客户端,用于基于 RSocket 的服务。

@RSocketClient
interface GreetingsClient {

	@MessageMapping("hello")
	Mono<String> hello(Mono<String> name);
}

Kubernetes Java 客户端和 Spring Native

然后,我将注意力转向使 Kubernetes Java 客户端在 Spring Native 和 GraalVM 上下文中良好运行。如果您想为 Kubernetes 构建内存高效的控制器和运算符,Kubernetes Java 客户端至关重要。我是否提到过 GraalVM 原生镜像 *非常* 内存高效?当然,这取决于您在应用程序中执行的操作,但我的典型应用程序最终会占用 40 到 55 兆字节的 RAM(具体来说是 RSS)。此外,启动时间仅为几十毫秒。官方的 Kubernetes-for-Java 客户端具有 Spring Boot 自动配置。因此,我所要做的就是编写 在 Spring Native 和 GraalVM 上下文中使此类应用程序良好运行所需的简单 Spring Native 配置我在这里详细解释了它。需要说明的是,现在可以使用您最喜欢的开发框架不仅构建出色的 Kubernetes 资源和控制器,而且还可以以低占用方式将它们部署到您组织的集群中。

Fabric8 和 Spring Native

说到 Kubernetes 客户端,我还让 RedHat 的出色 Fabric8.io Kubernetes 客户端 也与 Spring Native 一起工作。我发现了一个很棒的示例运算符和自定义资源定义,然后我使用我的 Fabric8 Spring Native 提示 使其工作。这是一个更完整的功能示例,并且运行良好。这是基于 Rohan Kanojia 的一个很棒的示例,我发现并将其改编为使用 Spring Boot 和 Spring Native。

这种方法有前景!在 Spring Native、官方的 Kubernetes Java 客户端和 Fabric8 客户端之间,没有理由不使用 Spring Boot 来构建您的下一个 Kubernetes 运算符。

Spring GraphQL 和 Spring Native

然后,我将注意力转向 Spring GraphQl 和 Spring Native。Spring GraphQL 运行得非常好,只要您覆盖 GraphQlSourceBuilder 如何派生用于为引擎提供 GraphQL 端点架构的 Spring Framework Resource 实例即可。它不像它那样容易,但仍然只需要额外的 @Bean 或两行代码左右就能使其工作。很好。当您使用 Spring GraphQL 并希望查询 Spring GraphQL 架构本身的元模型时,问题就开始了。例如,当您使用 /graphiql/ 交互式控制台查询数据时,拥有 GraphQL 元模型非常方便。*那* 需要做一些工作,但我做到了。我在 这篇文章中进一步解释了这一点

有了它,我可以像这样部署一个 GraphQL 控制器


@Controller
class CustomerGraphQlController {

	private final CustomerRepository repository;
 	
 	CustomerGraphQlController(CustomerRepository repository) {
 		this.repository = repository ;
 	} 

	@QueryMapping
	Flux<Customer> customers() {
		return this.repository.findAll();
	}
}

record Customer(@Id Integer id, String name) {
}

…它使用以下架构

type Query {
    customers : [Customer]
}
type Customer {
    id: ID
    name :String
}

然后在 https://127.0.0.1:8080/graphiql/ 上打开示例并发出以下查询

query {
 customers { id, name }
}

并获得我预期的结果!

其他

我也一直在处理许多其他我想与 Spring Native 一起使用的内容。因此,这是 CommonMark(Java 中的 Markdown 解析器) 的 Spring Native 配置。

为了使Apache Lucene在Spring Native项目中工作,我不得不添加各种类。当然,这个示例更复杂,使用了GraalVM替换和一个典型的Spring Native配置。但它确实有效,而且效果很好!

哦,我有没有提到我与Ronald Dehuysser合作,使Jobrunr(一个分布式作业调度引擎)在具有Spring Native的GraalVM环境中工作?因为我确实做了,结果是棒极了

所有这些工作我都在过去几周内完成:可能性是无限的,我迫不及待地想看到更多Spring世界中涌现出GraalVM集成。

获取Spring新闻

关注Spring新闻

订阅

走在前面

VMware提供培训和认证,帮助您快速提升。

了解更多

获取支持

Tanzu Spring通过一个简单的订阅提供OpenJDK™、Spring和Apache Tomcat®的支持和二进制文件。

了解更多

即将举行的活动

查看Spring社区中所有即将举行的活动。

查看全部