# spring-cloud-webflux **Repository Path**: zcq8292228/spring-cloud-webflux ## Basic Information - **Project Name**: spring-cloud-webflux - **Description**: 全栈响应式编程 微服务项目dome - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 4 - **Forks**: 0 - **Created**: 2021-04-06 - **Last Updated**: 2023-05-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README **1、响应式编程常用官网学习地址** 反应编程Reatvie project : https://projectreactor.io/docs/core/release/reference/ webflux 官网: https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-controller R2DBC官网: https://r2dbc.io/ spring data r2dbc -mysql: https://github.com/spring-projects/spring-data-r2dbc r2dbc官网: https://r2dbc.io/spec/0.8.3.RELEASE/spec/html/ **一、Webflux事务管理应用** **1、手动事务** 1.1 创建事务管理器 创建ReactiveTransactionManager和TransactionalOperator public class R2dbcConfiguration { @Bean public ReactiveTransactionManager transactionManager(ConnectionFactory connectionFactory) { return (new R2dbcTransactionManager(connectionFactory)); } @Bean public TransactionalOperator transactionalOperator(ReactiveTransactionManager transactionManager) { return TransactionalOperator.create(transactionManager); } } 1.2、注入TransactionalOperator @Component public class MyWebHandler { @Autowired private TransactionalOperator transactionalOperator; 1.3、 方法添加事务支持 public Mono saveMany(ServerRequest serverRequest) { return serverRequest.bodyToFlux(Product.class) .flatMap(i -> productService.save(i)) .then(ServerResponse.ok().build()) .as(transactionalOperator::transactional);//手动使用事务 } **2、使用注解管理事务** 2.1 注解启用事务管理 @SpringBootApplication @EnableTransactionManagement //注解启动事务管理 public class WebfluxApplication { public static void main(String[] args) { SpringApplication.run(WebfluxApplication.class, args); } 2.2 方法注解使用事务管理 /** * 保存多个商品 * @param serverRequest * @return */ @Transactional public Mono saveMany(ServerRequest serverRequest) { return serverRequest.bodyToFlux(Product.class) .flatMap(i -> productService.save(i)) .then(ServerResponse.ok().build()); //.as(transactionalOperator::transactional);//手动使用事务 } **二、webflux添加spring Security支持** 1、添加spring security依赖支持 org.springframework.boot spring-boot-starter-security 2、 添加 ReactiveUserDetailService @Configuration @EnableWebFluxSecurity public class SecurityConfigurer { @Bean public ReactiveUserDetailsService userDetailsService() { var admin = User.withDefaultPasswordEncoder() .username("admin") .password("123456") .roles("ADMIN") .build(); var guest = User.withDefaultPasswordEncoder() .username("user") .password("123456") .roles("GUEST") .build(); return (new MapReactiveUserDetailsService(admin, guest)); } 2.3 添加安全规则 对于Put delete post 请求需要admin权限,其它进行basic校验。 @Bean SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { return http.authorizeExchange() .pathMatchers(HttpMethod.PUT, "/route/product/**") .hasAnyRole("ADMIN") .pathMatchers(HttpMethod.POST, "/route/product/**") .hasAnyRole("ADMIN") .pathMatchers("/route/product/**") .authenticated() .pathMatchers("/route/product/**").access(((mono, object) -> mono.map(auth -> { var httpMethod = object.getExchange().getRequest().getMethod(); var granted = false; if (httpMethod == HttpMethod.PUT || httpMethod == HttpMethod.POST || httpMethod == HttpMethod.DELETE) { granted = auth.getAuthorities() .stream() .map(GrantedAuthority::getAuthority) .anyMatch("ROLE_ADMIN"::equals); } else { granted = auth.isAuthenticated(); } return (new AuthorizationDecision(granted)); }).switchIfEmpty(Mono.justOrEmpty(new AuthorizationDecision(false))))) .anyExchange() .permitAll() .and() .httpBasic() .and().csrf().disable() .build(); } 2.4 、测试验证 1、测试案例 测试案例: 保存商品 测试过程: 1、未添加Authorization 。 2、添加Authorization,用户 user 密码123456。 3、添加Authorization,用户 admin 密码123456。 2、 测试过程 2.1 未添加Authorization 不添加authorization信息,点击保存,弹框需要输入用户名和密码 。测试通过。 2.2、权限不够测试 添加Authorization,用户 user 密码123456, 响应403错误 禁止访问。 测试通过 2.3、权限正常测试 添加Authorization,用户 admin 密码123456, 响应200, 返回保存商品结果。 测试通过 **三、webflux服务注册与发现** 1、添加Nacos依赖 com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery org.springframework.cloud spring-cloud-dependencies Hoxton.SR4 pom import com.alibaba.cloud spring-cloud-alibaba-dependencies 2.2.1.RELEASE pom import 2、配置文件修改 cloud: nacos: discovery: server-addr: localhost:8848 # 注册中心地址 cluster-name: bole #集群名称 metadata: version: v1.0 3、服务注册 启动服务 reative-stock-service reative-product-service 3、服务之间调用 3.1 创建webclient @Bean public WebClient.Builder loadBalancedWebClientBuilder() { return WebClient.builder().baseUrl("http://reative-stock-service"); } 3.2 注入webclient @Component public class MyWebHandler { @Autowired private WebClient.Builder builder; 3.3 服务访问方式 /** * 通过webclient访问reactor-stock-service * @param serverRequest * @return */ public Mono findStock(ServerRequest serverRequest){ var productId = Integer.parseInt(serverRequest.pathVariable("productId")); System.out.println("productId:"+productId); return builder.build() .get().uri("/stock/get/{productId}",productId) .retrieve().bodyToMono(String.class) .flatMap(p -> ServerResponse.ok().bodyValue(p)); } reactor-stock-service 代码如下: @RestController @RequestMapping("/stock") public class StockController { @GetMapping("/get/{productId}") public Mono get(@PathVariable("productId") Long productId) { System.out.println("productId:" + productId); return Mono.just(100); } } 3.4 测试 测试案例: reactor-product-service查询库存服务服务 reactor-stock-service 商品ID=26的库存 期望:返回100 实际: 返回100 结果: 测试通过 **四、webflux负载均衡** 这里引入支持反应式的spring cloud load balancer , 没有采用ribbon(ribbon目前不支持reactive) 1、引入依赖 org.springframework.cloud spring-cloud-starter-loadbalancer 2、webclient添加支持负载均衡 @Bean @LoadBalanced //支持负载均衡 public WebClient.Builder loadBalancedWebClientBuilder() { return WebClient.builder().baseUrl("http://reative-stock-service"); } 3、禁用ribbon 负载均衡 配置文件需要禁用ribbon 负载均衡, 使用spring cloud load balancer负载均衡。 loadbalancer: ribbon: enabled: false 4、测试 1、 测试案例 测试案例:商品服务多次查询库存服务 测试过程: reactive-stock-service 启用两个服务,端口分布为9996 ,9999 商品服务4次查询库存服务,正常情况每个服务接收到2次请求(默认负载均衡是轮训算法)。 期望: 1、正常返回库存100 状态200 2、reactive-stock-service 两个服务9996 ,9999日志分别打印2次 结果: 测试通过 2、测试过程 发起4次查询库存请求 reactive-product-service 打印4次请求,日志显示库存服务9996,9998分别请求2次,符合期望。 reactive-stock-service 库存服务9996,9998分别收到请求2次,符合期望。测试通过!