- PVSM.RU - https://www.pvsm.ru -

Пример реактивного приложения Spring (релиз от 14.01.2020)

Счастливого запоздалого Нового года, 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.1

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 Moore

В семействе проектов 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.2

Реактивная поддержка изначально была включена в 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 1.0

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 5.2

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 2.2

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