- PVSM.RU - https://www.pvsm.ru -
Счастливого запоздалого Нового года, Spring коммьюнити!
Так как начинается очередной удивительный год разработки и улучшений в экосистеме Spring, хочу поделиться с вами обновленным примером приложения, демонстрирующего часть прогресса, достигнутого в портфеле проектов Spring в части поддержки Реактивной модели программирования.
Образец приложения BookStore Service Broker [1] был обновлен для демонстрации интеграции нескольких различных проектов Spring, включая Spring Cloud Open Service Broker, Spring Data, Spring Security, Spring HATEOAS и, конечно, Spring WebFlux и Spring Boot. Все эти проекты имеют версии GA, включающие Реактивную поддержку и готовые к продакшену в ваших собственных приложениях и сервисах.
Переведено @middle_java [2]
Для простоты само приложение функционирует и как брокер, и как экземпляр сервиса. Хотя сами брокеры придерживаются API Open Service Broker, предоставляемые ими услуги определяются более абстрактно. Сервисы могут делать или быть практически чем угодно. В случае нашего приложения, для каждого экземпляра сервиса создается новый набор учетных данных. Эти учетные данные используются в запросах к экземпляру сервиса. URL-адрес нового экземпляра сервиса задается таким же, как и маршрут до самого брокера. Таким образом, учетные данные используются для разделения запросов к различным экземплярам сервиса. Целью было разработать снабженный всем необходимым пример, демонстрирующий многие части портфеля проектов Spring.
Spring Cloud Open Service Broker [3] — это платформа для создания приложений Spring Boot, реализующих API Open Service Broker, и позволяющая разработчикам предоставлять услуги приложениям, работающим в облачных платформах, таких как Cloud Foundry, Kubernetes и OpenShift. Начиная с версии 3.0, Spring Cloud Open Service Broker поддерживает веб-фреймворки Spring WebFlux и Spring MVC с помощью Реактивных типов в интерфейсах контроллера и сервиса.
Чтобы начать работу со Spring Cloud Open Service Broker, включите в ваше приложение стартер Spring Boot:
implementation('org.springframework.cloud:spring-cloud-starter-open-service-broker:3.1.0.RELEASE')
Затем реализуем ServiceInstateService и ServiceInstateBindingService. Следующий код иллюстрирует необходимый 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 [4] Реактивная поддержка изначально была представлена в Spring Data Kay [5]. Spring Data R2DBC недавно анонсировал выпуск GA-релиза, однако Spring Boot пока еще не имеет GA-релиза с интеграцией со Spring Data R2DBC. В этом примере в качестве резервного хранилища данных используется MongoDB.
Чтобы начать работу с Reactive MongoDB, включите в ваше приложение стартер Spring Boot:
implementation('org.springframework.boot:spring-boot-starter-data-mongodb-reactive')
Для демонстрации добавим встроенный сервер MongoDB:
implementation('de.flapdoodle.embed:de.flapdoodle.embed.mongo')
Затем настроим Реактивный репозиторий:
@Configuration
@EnableReactiveMongoRepositories(basePackageClasses = {
ServiceBrokerRepositoryPackageMarker.class,
WebRepositoryPackageMarker.class
})
public class ApplicationRepositoryConfiguration {
}
Наконец, определим ReactiveCrudRepository. Следующий интерфейс — один из примеров из образца приложения:
public interface ServiceInstanceRepository extends ReactiveCrudRepository < ServiceInstance, String > {
}
Реактивная поддержка изначально была включена в Spring Security 5 [6] и интеграция со Spring Boot и Spring Framework продолжает развиваться.
Для использования Spring Security добавьте стартер Spring Boot:
implementation('org.springframework.boot:spring-boot-starter-security')
Затем определим конфигурацию безопасности с помощью @EnableWebCardingSecurity. Этот код иллюстрирует, как одно приложение защищает эндпоинты брокера /v2 и /bookstars, отвечающие на запросы экземпляров сервиса:
@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;
}
}
Наконец, оценщики разрешений (permission evaluators) не поддерживаются в контроллерах WebFlux, но мы можем добиться аналогичной функциональности, вызвав бин в выражении SpEL и передав объект 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);
}
В этом примере анализируются полномочия для определения наличия идентификатора книжного магазина:
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 [7] 1.0 GA был выпущен недавно и включает в себя Реактивную поддержку создания ссылок и моделирования представлений.
Добавьте стартер Spring HATEOAS, чтобы активировать автоматическую конфигурацию Spring Boot. Поскольку мы создаем Реактивное приложение Spring WebFlux, нужно исключить стартер Spring Web:
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 Framework [8] 5 изначально предложил Реактивную поддержку в новом веб-фреймворке Spring WebFlux. Кроме того, новые WebClient и WebTestClient включают поддержку использования и тестирования приложений Spring WebFlux.
Чтобы использовать их, просто добавьте стартеры Spring Boot:
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 [9] объединяет все эти проекты, предлагая автоконфигурирование Реактивной поддержки в Spring WebFlux, Spring Data, Spring Security, Spring HATEOAS, а также в инструментах тестирования. Во многих случаях реализация только требует добавить определенные стартеры Spring Boot или связанные зависимости для активации функциональности.
Этот пост включает краткое введение в Реактивную поддержку в некоторых проектах Spring. По мере того, как все больше проектов Spring адаптируются и поддерживают Реактивные API, у разработчиков будет появляться больше выбора использовать в своих приложениях императивное или же реактивное программирование. Кроме того, этот пример приложения демонстрирует только часть проектов Spring, которые сейчас предлагают Реактивную поддержку. В будущем ищите больше! Если у вас есть вопросы или проблемы по конкретному проекту Spring, свяжитесь, пожалуйста, с сопровождающими проекта на соответствующей странице GitHub.
Переведено @middle_java [2]
Автор: middle_java
Источник [10]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/java/344502
Ссылки в тексте:
[1] BookStore Service Broker: https://github.com/spring-cloud-samples/bookstore-service-broker
[2] @middle_java: http://tele.gg/middle_java
[3] Spring Cloud Open Service Broker: https://spring.io/projects/spring-cloud-open-service-broker
[4] Spring Data: https://spring.io/projects/spring-data
[5] Spring Data Kay: https://spring.io/blog/2016/11/28/going-reactive-with-spring-data
[6] Spring Security 5: https://spring.io/projects/spring-security
[7] Spring HATEOAS: https://spring.io/projects/spring-hateoas
[8] Spring Framework: https://spring.io/projects/spring-framework
[9] Spring Boot: https://spring.io/projects/spring-boot
[10] Источник: https://habr.com/ru/post/485498/?utm_source=habrahabr&utm_medium=rss&utm_campaign=485498
Нажмите здесь для печати.