GraalVM 原生支援

Spring Framework 6.0 引入了將 Spring 應用程式編譯為 GraalVM Native Image 的支援基礎架構。如果您不熟悉 GraalVM,它與部署在 JVM 上的應用程式有何不同,以及對於 Spring 應用程式的意義,請參閱專門的 Spring Boot 3.x GraalVM Native Image 支援文件。Spring Boot 也記錄了 Spring 中 GraalVM 支援的已知限制

GraphQL Java metadata

由於 應用程式的靜態分析是在建置時完成的,如果您的應用程式在執行時尋找靜態資源、執行反射或建立 JDK 代理,GraalVM 可能需要額外的提示。

GraphQL Java 在執行時執行三項任務,這些任務對 Native Image 很敏感

  1. 載入訊息國際化的資源包

  2. 對內部類型進行一些反射以進行架構檢查

  3. 反射您的應用程式向架構註冊的 Java 類型。例如,當 GraphQL Java 從應用程式類型中獲取屬性時,就會發生這種情況

前兩項透過 Spring 團隊貢獻給 GraalVM reachability metadata repository 的 reachability metadata 處理。當建置依賴 GraphQL Java 的應用程式時,原生編譯工具會自動擷取此 metadata。這不包括我們列表中的第三項,因為這些類型是由應用程式本身提供的,必須透過另一種方式發現。

原生伺服器應用程式支援

在典型的 Spring for GraphQL 應用程式中,與 GraphQL 架構綁定的 Java 類型會在 @Controller 方法簽章中作為參數或回傳類型公開。在建置的 預先編譯處理階段 期間,Spring 或 GraphQL 將使用其 o.s.g.data.method.annotation.support.SchemaMappingBeanFactoryInitializationAotProcessor 來發現相關類型並相應地註冊 reachability metadata。如果您正在使用 GraalVM 支援建置 Spring Boot 應用程式,則所有這些都會自動為您完成。

如果您的應用程式「手動」註冊資料提取器,則某些類型將無法被發現。然後您應該使用 Spring Framework 的 @RegisterReflectionForBinding 註冊它們

import graphql.schema.DataFetcher;

import org.springframework.aot.hint.annotation.RegisterReflectionForBinding;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.graphql.data.query.QuerydslDataFetcher;
import org.springframework.graphql.execution.RuntimeWiringConfigurer;

@Configuration
@RegisterReflectionForBinding(Book.class) (3)
public class GraphQlConfiguration {

	@Bean
	RuntimeWiringConfigurer customWiringConfigurer(BookRepository bookRepository) { (1)
		DataFetcher<Book> dataFetcher = QuerydslDataFetcher.builder(bookRepository).single();
		return (wiringBuilder) -> wiringBuilder
				.type("Query", (builder) -> builder.dataFetcher("book", dataFetcher)); (2)
	}

}
1 此應用程式宣告一個 RuntimeWiringConfigurer,它「手動」新增一個 DataFetcher
2 透過此 DataFetcherBookRepository 將公開 Book 類型
3 @RegisterReflectionForBinding 將為 Book 類型和所有作為欄位公開的類型註冊相關提示

用戶端支援

GraphQlClient 不一定作為 bean 存在於應用程式上下文中,並且它不會在方法簽章中公開架構中使用的 Java 類型。因此,無法使用上一節中描述的 AotProcessor 策略。為了提供用戶端支援,Spring for GraphQL 嵌入了 用戶端基礎架構的相關 reachability metadata。當涉及到應用程式使用的 Java 類型時,應用程式應使用與使用 @RegisterReflectionForBinding 的「手動」資料提取器類似的策略

import reactor.core.publisher.Mono;

import org.springframework.aot.hint.annotation.RegisterReflectionForBinding;
import org.springframework.graphql.client.GraphQlClient;
import org.springframework.stereotype.Component;

@Component
@RegisterReflectionForBinding(Project.class) (2)
public class ProjectService {

	private final GraphQlClient graphQlClient;

	public ProjectService(GraphQlClient graphQlClient) {
		this.graphQlClient = graphQlClient;
	}

	public Mono<Project> project(String projectSlug) {
		String document = """
				query projectWithReleases($projectSlug: ID!) {
					project(slug: $projectSlug) {
						name
						releases {
							version
						}
					}
				}
				""";

		return this.graphQlClient.document(document)
				.variable("projectSlug", projectSlug)
				.retrieve("project")
				.toEntity(Project.class); (1)
	}
}
1 在 Native Image 中,我們需要確保可以在執行時對 Project 執行反射
2 @RegisterReflectionForBinding 將為 Project 類型和所有作為欄位公開的類型註冊相關提示