響應式書店服務代理

工程 | Roy Clarkson | January 14, 2020 | ...

遲來的新年快樂,Spring 社群的朋友們!當我們開始 Spring 專案生態系統中又一個精彩的開發和進步之年時,我想與大家分享一個更新的示例應用程式,它代表了我們在整個產品組合中為支援響應式程式設計模型所取得的一些進展。

BookStore Service Broker 示例應用程式已更新,以演示多個 Spring 專案的整合,包括 Spring Cloud Open Service Broker, Spring Data, Spring Security, Spring HATEOAS, 當然還有 Spring WebFlux 和 Spring Boot。所有這些專案都有包含響應式支援的 GA 版本,並已準備好在您自己的應用程式和服務中投入生產使用。

為簡單起見,該應用程式本身既充當服務代理,也充當服務例項。服務代理本身遵循 Open Service Broker API,而它們提供的服務則定義得更抽象。服務幾乎可以做任何事情或代表任何事物。對於此應用程式而言,會為每個配置的服務例項建立一組新的憑證。這些憑證用於向服務例項發出請求。新服務例項的 URL 配置為與服務代理本身的路由相同。透過這種方式,憑證用於區分對各種服務例項的請求。目標是設計一個自包含、全面的示例,以展示 Spring 產品組合的多個部分。

Spring Cloud Open Service Broker 3.1

Spring Cloud Open Service Broker 是一個用於構建實現 Open Service Broker API 的 Spring Boot 應用程式的框架,它允許開發人員將服務交付給在 Cloud Foundry、Kubernetes 和 OpenShift 等雲原生平臺上執行的應用程式。自 3.0 版本以來,Spring Cloud Open Service Broker 透過控制器和服務介面中的響應式型別支援 Spring WebFlux 和 Spring MVC Web 框架。

要開始使用 Spring Cloud Open Service Broker,請在您的應用程式中包含 Spring Boot starter

implementation('org.springframework.cloud:spring-cloud-starter-open-service-broker:3.1.0.RELEASE')

接下來,實現 ServiceInstanceServiceServiceInstanceBindingService。以下程式碼說明了所需的 API。檢視示例應用程式瞭解完整詳情。

@Service
public class BookStoreServiceInstanceService
		implements ServiceInstanceService {

	@Override
	public Mono<CreateServiceInstanceResponse> createServiceInstance(
		CreateServiceInstanceRequest request) {...}

	@Override
	public Mono<GetServiceInstanceResponse> getServiceInstance(
		GetServiceInstanceRequest request) {...}

	@Override
	public Mono<DeleteServiceInstanceResponse> deleteServiceInstance(
		DeleteServiceInstanceRequest request) {...}

}

Spring Data Moore

Spring Data 釋出列車最初在 Spring Data Kay 中引入了響應式支援。Spring Data R2DBC 最近釋出了 GA 版本,但是 Spring Boot 尚未釋出整合 Spring Data R2DBC 的 GA 版本。本示例使用 MongoDB 作為後端資料儲存。

要開始使用 Reactive MongoDB,請新增 Spring Boot starter

implementation('org.springframework.boot:spring-boot-starter-data-mongodb-reactive')

為了演示目的,新增一個嵌入式 MongoDB 伺服器

implementation('de.flapdoodle.embed:de.flapdoodle.embed.mongo')

接下來,配置 Reactive repository

@Configuration
@EnableReactiveMongoRepositories(basePackageClasses = {
		ServiceBrokerRepositoryPackageMarker.class,
		WebRepositoryPackageMarker.class
})
public class ApplicationRepositoryConfiguration {
}

最後,定義一個 ReactiveCrudRepository。以下介面是示例應用程式中的一個示例

public interface ServiceInstanceRepository extends ReactiveCrudRepository<ServiceInstance, String> {
}

Spring Security 5.2

響應式支援最初包含在 Spring Security 5 中,並且與 Spring Boot 和 Spring Framework 的整合持續成熟。

要使用 Spring Security,請包含 Spring Boot starter

implementation('org.springframework.boot:spring-boot-starter-security')

接下來,使用 `@EnableWebFluxSecurity` 定義安全配置。此程式碼展示了單個應用程式如何同時保護 `/v2` 處的服務代理端點以及響應服務例項請求的 `/bookstores` 端點

@Configuration
@EnableWebFluxSecurity
public class SecurityConfiguration {

	@Bean
	public SecurityWebFilterChain securityWebFilterChain(
		ServerHttpSecurity http) {
		return http
				.csrf().disable()
				.httpBasic()
				.and().authorizeExchange()
				.pathMatchers("/bookstores/**").authenticated()
				.pathMatchers("/v2/**").hasAuthority(
					SecurityAuthorities.ADMIN)
				.matchers(EndpointRequest.to("info", "health")).permitAll()
				.matchers(EndpointRequest.toAnyEndpoint()).hasAuthority(
					SecurityAuthorities.ADMIN)
				.and().build();
	}

	@Bean
	public PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}

}

接下來,實現一個 ReactiveUserDetailsService

@Service
public class RepositoryUserDetailsService implements
		ReactiveUserDetailsService {

	private final UserRepository userRepository;

	public RepositoryUserDetailsService(UserRepository userRepository) {
		this.userRepository = userRepository;
	}

}

最後,WebFlux 控制器不支援許可權評估器,但我們可以透過在 SpEL 表示式中呼叫 bean 並傳遞 Authentication 物件來實現類似的功能

@GetMapping("/{bookStoreId}")
@PreAuthorize("hasAnyRole('ROLE_FULL_ACCESS','ROLE_READ_ONLY') and
@bookStoreIdEvaluator.canAccessBookstore(authentication, #bookStoreId)")
public Mono<ResponseEntity<BookStoreResource>> getBooks(
	@PathVariable String bookStoreId) {
	return bookStoreService.getBookStore(bookStoreId)
			.flatMap(this::createResponse);
}

在此示例中,解析許可權以確定書店 ID 的存在

public boolean canAccessBookstore(Authentication authentication,
		String bookStoreId) {
	return authentication.getAuthorities().stream()
			.filter(authority -> authority.getAuthority()
					.startsWith(BOOK_STORE_ID_PREFIX))
			.map(authority -> {
				String serviceInstanceId = authority.getAuthority()
						.substring(BOOK_STORE_ID_PREFIX.length());
				return serviceInstanceId.equals(bookStoreId);
			})
			.findFirst()
			.orElse(true);
}

Spring HATEOAS 1.0

Spring HATEOAS 1.0 GA 最近釋出,其中包括對連結建立和表示模型化的響應式支援。

包含 Spring HATEOAS starter 以啟用 Spring Boot 自動配置。由於我們正在構建一個響應式 Spring WebFlux 應用程式,我們需要排除 Spring Web starter

implementation('org.springframework.boot:spring-boot-starter-hateoas') {
		exclude group: 'org.springframework.boot', module: 'spring-boot-starter-web'
}

接下來,您可以使用 WebFluxLinkBuilder 組裝 Hypermedia 資源

public Mono<BookResource> toModel(Book book, String bookStoreId) {
		return Mono.just(new BookResource(book))
				.flatMap(bookResource -> linkTo(methodOn(
					BookController.class).getBook(bookStoreId, book.getId()))
						.withSelfRel()
						.toMono()
						.flatMap(link -> Mono.just(bookResource.add(link)))
						.thenReturn(bookResource));
	}

然後您可以在控制器的響應體中使用該資源

return new BookStoreResourceAssembler().toModel(bookStore)
		.flatMap(bookStoreResource -> Mono.just(new ResponseEntity<>(bookStoreResource, HttpStatus.OK)));

Spring 框架 5.2

Spring 框架 5 最初在新的 Spring WebFlux Web 框架中提供了響應式支援。此外,新的 WebClientWebTestClient 包含對使用和測試 Spring WebFlux 應用程式的支援。

要使用這些,只需包含 Spring Boot starters

implementation('org.springframework.boot:spring-boot-starter-webflux')
testImplementation('org.springframework.boot:spring-boot-starter-test') {
	exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}

例如,使用 WebTestClient 驗證控制器功能

this.client.get().uri("/bookstores/{bookStoreId}", bookStoreId)
		.accept(MediaType.APPLICATION_JSON)
		.exchange()
		.expectStatus().isEqualTo(HttpStatus.OK);

Spring Boot 2.2

Spring Boot 透過為 Spring WebFlux, Spring Data, Spring Security, Spring HATEOAS 中的響應式支援以及測試工具提供自動配置,將所有這些專案整合在一起。在許多情況下,實現功能只需要包含特定的 Spring Boot Starters 或相關的依賴項。

結論

本文簡要介紹了部分 Spring 專案中的響應式支援。隨著更廣泛的 Spring 產品組合持續採用和支援響應式 API,開發人員在應用程式中選擇使用命令式還是響應式程式設計風格將擁有更多選擇。此外,此示例應用程式僅展示了目前提供響應式支援的 Spring 專案的一部分。未來還會有更多!如果您對特定的 Spring 專案有疑問或問題,請在該專案相關的 GitHub 頁面上聯絡維護者。

獲取 Spring 簡報

透過 Spring 簡報保持聯絡

訂閱

提升自己

VMware 提供培訓和認證,助您快速提升。

瞭解更多

獲取支援

Tanzu Spring 透過一項簡單的訂閱提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案。

瞭解更多

即將舉行的活動

檢視 Spring 社群所有即將舉行的活動。

檢視全部