To learn how to properly refactor to reactive
The goal of this step is to demonstrate how to start refactoring of the existing Microservices System in the way you will not break the whole system by introducing Reactive Programming concept with Project Reactor and WebFlux
The very first step you should start with is adding the
implementation 'org.springframework.boot:spring-boot-starter-webflux'dependency in all the places you have web module. This will keep WebMVC module as a priority one but
will add support for Reactive Types
and WebClient
Modify HttpAuthenticationService to use WebClient
Remember. The API should remain imperative on this Step. Use method
.block()to convert Reactive to Imperative
Run ServiceIntegrationTest to ensure functionality has not been broken during the modification
At the moment we have delivery.app.common.security.web.client.JWTHeadersClientRequestCustomizer
responsible for adding Authorization: Bearer ... header to a request. If we replace RestTemplate
, we need to make sure WebClient offers same functionality. For that purpose
use org.springframework.web.reactive.function.client.ExchangeFilterFunction
which is a new intercepting mechanism for WebClient and implement same logic was before.
Note: in new Reactive Web networking
ClientRequestis an immutable entity. UseClientRequest.from(origin)....build()to modify it inExchengeFilterFunction.
Finally, modify the BaseConfiguration class, and define a WebClientCustomizer bean to introduce
created ExchengeFilterFunction.
The simples Http integration which uses Auth functionality is in CartService rework it
to WebClient support.
Remember. The API should remain imperative on this Step. Use method
.block()to convert Reactive to Imperative
Add R2dbc support by replacing
implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'with
implementation 'org.springframework.boot:spring-boot-starter-data-r2dbc'
implementation("io.r2dbc:r2dbc-h2")Also, make sure your are modifying application.yaml and adding replacing old datasource config:
spring:
datasource:
url: jdbc:h2:file:./build/data/usersdb
driverClassName: org.h2.Driver
username: sa
password: passwordwith a new one:
spring:
r2dbc:
url: r2dbc:h2:file:///./build/data/usersdb
username: sa
password: passwordRemember. The API should remain imperative on this Step. Use method
.block()to convert Reactive to Imperative
At this step we will refactor completely to WebFlux but at the places where it is really needed!
- Remove WebMVC dependency from the service
Note: module
commonsmay still bring an old WebMVC dependency. Exclude it fromgateway-service/build.gradleusingconfigurations.implementation { exclude group: 'org.springframework.boot', module: 'spring-boot-starter-web' }
- Rework Security Configuration to Support WebFlux Security. Replace the old
SecurityConfigwith the following one@EnableWebFluxSecurity public class SecurityConfig { @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http .authorizeExchange((exchanges) -> exchanges .pathMatchers("/login").permitAll() .pathMatchers("/css/**", "/index").permitAll() .pathMatchers(HttpMethod.GET, "/api/products", "/api/products/*").permitAll() .anyExchange().authenticated() ) .formLogin((formLogin) -> formLogin .loginPage("/login") ); return http.build(); } }
- Rebase
RemoteAuthenticationMangerto extendReactiveAuthenticationManager - Migrate
RoutingControllerto use Reactive Types from end to end. UseDataBufferclass instead ofResourcepublic Mono<ResponseEntity<Flux<DataBuffer>>> handle( @PathVariable("service") String service, @Nullable @PathVariable(value = "path", required = false) String path, HttpEntity<Flux<DataBuffer>> httpEntity, HttpMethod httpMethod ) { // new impl }
