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 import2、配置文件修改
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次,符合期望。测试通过!
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。