Как стать автором
Обновить

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

Время на прочтение6 мин
Количество просмотров7.5K
Автор оригинала: Roy Clarkson
Счастливого запоздалого Нового года, Spring коммьюнити!

Так как начинается очередной удивительный год разработки и улучшений в экосистеме Spring, хочу поделиться с вами обновленным примером приложения, демонстрирующего часть прогресса, достигнутого в портфеле проектов Spring в части поддержки Реактивной модели программирования.

Образец приложения BookStore Service Broker был обновлен для демонстрации интеграции нескольких различных проектов Spring, включая Spring Cloud Open Service Broker, Spring Data, Spring Security, Spring HATEOAS и, конечно, Spring WebFlux и Spring Boot. Все эти проекты имеют версии GA, включающие Реактивную поддержку и готовые к продакшену в ваших собственных приложениях и сервисах.

Переведено @middle_java

Для простоты само приложение функционирует и как брокер, и как экземпляр сервиса. Хотя сами брокеры придерживаются API Open Service Broker, предоставляемые ими услуги определяются более абстрактно. Сервисы могут делать или быть практически чем угодно. В случае нашего приложения, для каждого экземпляра сервиса создается новый набор учетных данных. Эти учетные данные используются в запросах к экземпляру сервиса. URL-адрес нового экземпляра сервиса задается таким же, как и маршрут до самого брокера. Таким образом, учетные данные используются для разделения запросов к различным экземплярам сервиса. Целью было разработать снабженный всем необходимым пример, демонстрирующий многие части портфеля проектов Spring.

Spring Cloud Open Service Broker 3.1


Spring Cloud Open Service Broker — это платформа для создания приложений 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 Реактивная поддержка изначально была представлена в Spring Data Kay. 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 и интеграция со 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 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 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 объединяет все эти проекты, предлагая автоконфигурирование Реактивной поддержки в Spring WebFlux, Spring Data, Spring Security, Spring HATEOAS, а также в инструментах тестирования. Во многих случаях реализация только требует добавить определенные стартеры Spring Boot или связанные зависимости для активации функциональности.

Заключение


Этот пост включает краткое введение в Реактивную поддержку в некоторых проектах Spring. По мере того, как все больше проектов Spring адаптируются и поддерживают Реактивные API, у разработчиков будет появляться больше выбора использовать в своих приложениях императивное или же реактивное программирование. Кроме того, этот пример приложения демонстрирует только часть проектов Spring, которые сейчас предлагают Реактивную поддержку. В будущем ищите больше! Если у вас есть вопросы или проблемы по конкретному проекту Spring, свяжитесь, пожалуйста, с сопровождающими проекта на соответствующей странице GitHub.

Переведено @middle_java
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Какую реактивную реализацию вы используете?
3.23% Akka Streams2
19.35% RxJava12
6.45% Vert.x4
40.32% WebFlux25
4.84% Другой3
33.87% Не использую21
Проголосовали 62 пользователя. Воздержались 18 пользователей.
Теги:
Хабы:
Всего голосов 8: ↑6 и ↓2+4
Комментарии4

Публикации

Истории

Работа

Ближайшие события