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
ClientRequest
is 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: password
with a new one:
spring:
r2dbc:
url: r2dbc:h2:file:///./build/data/usersdb
username: sa
password: password
Remember. 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
commons
may still bring an old WebMVC dependency. Exclude it fromgateway-service/build.gradle
usingconfigurations.implementation { exclude group: 'org.springframework.boot', module: 'spring-boot-starter-web' }
- Rework Security Configuration to Support WebFlux Security. Replace the old
SecurityConfig
with 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
RemoteAuthenticationManger
to extendReactiveAuthenticationManager
- Migrate
RoutingController
to use Reactive Types from end to end. UseDataBuffer
class instead ofResource
public 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 }