GraalVM 和 Spring Native

Hi,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提供了一种机制–hints–通过它你可以做到这一点。这很容易。但还是要做的。所以,我一直在寻找一些我认为可能需要一些帮助的项目,并试图让它们发挥作用。

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兆字节的内存(好吧,RSS,具体来说)。而这是在只有几十毫秒的启动时间之外的。官方Kubernetes-for-Java客户端有一个Spring Boot自动配置。因此,我所要做的就是写出琐碎的Spring Native配置,以使此类应用在Spring Native和GraalVM上下文中顺利运行。我在这里详细解释。可以说,现在有可能使用你最喜欢的开发框架,不仅建立优秀的Kubernetes资源和控制器,而且以低足迹的方式将它们部署到你组织的集群中。

Fabric8和Spring Native

说到Kubernetes客户端,我也得到了RedHat的神话般的Fabric8.io Kubernetes客户端Spring Native, too的工作。我发现了一个可爱的操作符和自定义资源定义的例子,然后我用我的Fabric8 Spring Native hints使之工作。这是一个功能更全面的例子,而且工作起来很有魅力。这是基于Rohan Kanojia的一个出色的例子,我找到了这个例子,并将其改编为使用Spring Boot和Spring Native。

这种方法很有说服力! 在Spring Native和官方Kubernetes Java客户端以及Fabric8客户端之间,没有理由不使用Spring Boot来构建你的下一个Kubernetes运营商。

Spring GraphQL和Spring Native

然后,我把注意力转向Spring GraphQl和Spring Native。只要你覆盖GraphQlSourceBuilder'如何派生Spring框架的Resource’实例,用于为引擎提供GraphQL端点的模式,Spring GraphQL就能很好地工作。这并不容易,但它仍然只是一个额外的@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
}

然后在http://localhost:8080/graphiql/上打开这个例子,并发出以下查询。

query {
 customers { id, name }
}

并得到我所期望的结果!

Miscellaneous

我也一直在处理许多其他我想用Spring Native工作的事情。所以这里是CommonMark,Java中的Markdown解析器的Spring Native配置。

以下是我为使Apache Lucene在Spring Native项目中工作而必须添加的各种类。当然,这个例子比较复杂,使用了GraalVM替换和一个典型的Spring Native配置。但它是可行的,而且是很好的!

哦,我有没有提到我和Ronald Dehuysser一起工作,让Jobrunr,一个分布式作业调度引擎,在GraalVM环境下与Spring Native一起工作?因为我做到了,而且结果是*棒的!

我是在过去几周内完成这些工作的:可能性是无穷的,我迫不及待地想看到越来越多的Springdom sprout GraalVM集成的广阔世界。


原文:Go, Go, GraalVM with Spring Native: My Adventures in Native Image-ville