add WebClient example (#3140)

pull/3156/head
YuLuo 2 years ago committed by GitHub
parent a2d91e56c5
commit a5e53dccaa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -21,6 +21,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>

@ -26,6 +26,21 @@ public final class Constants {
*/
public static final String CENTER_FLAG = "center";
/**
* Feign.
*/
public static final String FEIGN = "Feign";
/**
* RestTemplate.
*/
public static final String REST_TEMPLATE = "RestTemplate";
/**
* WebClient.
*/
public static final String WEB_CLIENT = "WebClient";
private Constants() {
}

@ -0,0 +1,38 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.example.common;
import java.util.List;
import com.alibaba.cloud.example.common.entity.Product;
import com.alibaba.cloud.example.common.entity.ResultHolder;
/**
* @author yuluo
*/
public interface ProductService {
ResultHolder<List<Product>> list();
ResultHolder<Product> detail(String rId, String pId);
ResultHolder<Product> detailHidden(String pId);
ResultHolder<String> buy(String rpcType, String rId, String pId, Integer number);
}

@ -25,6 +25,6 @@ public enum RPCType {
/**
* Spring Cloud.
*/
SpringCloud
SpringCloud,
}

@ -16,19 +16,17 @@
package com.alibaba.cloud.example.common.service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.alibaba.cloud.example.common.RPCType;
import com.alibaba.cloud.example.common.entity.Product;
import com.alibaba.cloud.example.common.entity.ResultHolder;
import com.alibaba.cloud.example.common.service.strategy.FeignProductService;
import com.alibaba.cloud.example.common.service.strategy.RestTemplateProductService;
import com.alibaba.cloud.example.common.service.strategy.WebClientProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.client.RestTemplate;
@Service
@ -38,61 +36,48 @@ public class ProductDAO {
RestTemplate restTemplate;
@Autowired
private ProductService productService;
private FeignProductService feignProductService;
@Autowired
private RestTemplateProductService restTemplateProductService;
@Autowired
private WebClientProductService webClientProductService;
public ResultHolder<List<Product>> list() {
return productService.list();
return feignProductService.list();
}
public ResultHolder<Product> detail(String rId, String pId) {
return productService.detail(rId, pId);
return feignProductService.detail(rId, pId);
}
public ResultHolder<Product> detailHidden(String pId) {
return productService.detailHidden(pId);
return feignProductService.detailHidden(pId);
}
public ResultHolder<String> buy(String rId, String pId, Integer number) {
return productService.buy(RPCType.SpringCloud.name(), rId, pId, number);
return feignProductService.buy(RPCType.SpringCloud.name(), rId, pId, number);
}
public ResultHolder<List<Product>> listTemplate() {
if (restTemplate != null) {
return restTemplate.getForObject("http://product/list", ResultHolder.class);
}
return productService.list();
}
public ResultHolder<List<Product>> listByRestTemplate() {
public ResultHolder<Product> detailTemplate(String rId, String pId) {
if (restTemplate != null) {
Map<String, String> params = new HashMap<>(2);
params.put("rId", rId);
params.put("pId", pId);
return restTemplate.getForObject("http://product/detail", ResultHolder.class,
params);
}
return productService.detail(rId, pId);
return restTemplateProductService.list();
}
@FeignClient(name = "product")
public interface ProductService {
public ResultHolder<Product> detailByRestTemplate(String rId, String pId) {
@RequestMapping("/list/")
ResultHolder<List<Product>> list();
return restTemplateProductService.detail(rId, pId);
}
@RequestMapping("/detail/")
ResultHolder<Product> detail(@RequestParam(name = "rId") String rId,
@RequestParam(name = "pId") String pId);
public ResultHolder<List<Product>> listByWebClient() {
@RequestMapping("/detailHidden/")
ResultHolder<Product> detailHidden(@RequestParam(name = "pId") String pId);
return webClientProductService.list();
}
@RequestMapping("/buy/")
ResultHolder<String> buy(@RequestParam(name = "rpcType") String rpcType,
@RequestParam(name = "rId") String rId,
@RequestParam(name = "pId") String pId,
@RequestParam(name = "number") Integer number);
public ResultHolder<Product> detailByWebClient(String rId, String pId) {
return webClientProductService.detail(rId, pId);
}
}

@ -0,0 +1,51 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.example.common.service.strategy;
import java.util.List;
import com.alibaba.cloud.example.common.entity.Product;
import com.alibaba.cloud.example.common.entity.ResultHolder;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @author yuluo
*/
@FeignClient(name = "product")
public interface FeignProductService {
@RequestMapping("/list/")
ResultHolder<List<Product>> list();
@RequestMapping("/detail/")
ResultHolder<Product> detail(@RequestParam(name = "rId") String rId,
@RequestParam(name = "pId") String pId);
@RequestMapping("/detailHidden/")
ResultHolder<Product> detailHidden(@RequestParam(name = "pId") String pId);
@RequestMapping("/buy/")
ResultHolder<String> buy(@RequestParam(name = "rpcType") String rpcType,
@RequestParam(name = "rId") String rId,
@RequestParam(name = "pId") String pId,
@RequestParam(name = "number") Integer number);
}

@ -0,0 +1,79 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.example.common.service.strategy;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.alibaba.cloud.example.common.ProductService;
import com.alibaba.cloud.example.common.entity.Product;
import com.alibaba.cloud.example.common.entity.ResultHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
/**
* @author yuluo
*/
@Component
public class RestTemplateProductService implements ProductService {
@Autowired(required = false)
RestTemplate restTemplate;
@Autowired
private FeignProductService feignProductService;
@Override
public ResultHolder<List<Product>> list() {
if (restTemplate != null) {
return restTemplate.getForObject("http://product/list", ResultHolder.class);
}
return feignProductService.list();
}
@Override
public ResultHolder<Product> detail(String rId, String pId) {
if (restTemplate != null) {
Map<String, String> params = new HashMap<>(2);
params.put("rId", rId);
params.put("pId", pId);
return restTemplate.getForObject("http://product/detail", ResultHolder.class,
params);
}
return feignProductService.detail(rId, pId);
}
@Override
public ResultHolder<Product> detailHidden(String pId) {
return feignProductService.detailHidden(pId);
}
@Override
public ResultHolder<String> buy(String rpcType, String rId, String pId,
Integer number) {
return feignProductService.buy(rpcType, rId, pId, number);
}
}

@ -0,0 +1,82 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.example.common.service.strategy;
import java.util.List;
import com.alibaba.cloud.example.common.ProductService;
import com.alibaba.cloud.example.common.entity.Product;
import com.alibaba.cloud.example.common.entity.ResultHolder;
import reactor.core.publisher.Mono;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
/**
* @author yuluo
*/
@Component
public class WebClientProductService implements ProductService {
@Autowired(required = false)
WebClient webClient;
@Autowired
private FeignProductService feignProductService;
@Override
public ResultHolder<List<Product>> list() {
if (webClient != null) {
Mono<ResultHolder> resultHolderMono = webClient.get()
.uri("http://product/list").retrieve().bodyToMono(ResultHolder.class);
return resultHolderMono.block();
}
return feignProductService.list();
}
@Override
public ResultHolder<Product> detail(String rId, String pId) {
if (webClient != null) {
Mono<ResultHolder> resultHolderMono = webClient.get()
.uri(uriBuilder -> uriBuilder.scheme("http").host("product")
.path("/detail").queryParam("rId", rId).queryParam("pId", pId)
.build())
.retrieve().bodyToMono(ResultHolder.class);
return resultHolderMono.block();
}
return feignProductService.detail(rId, pId);
}
@Override
public ResultHolder<Product> detailHidden(String pId) {
return feignProductService.detailHidden(pId);
}
@Override
public ResultHolder<String> buy(String rpcType, String rId, String pId,
Integer number) {
return feignProductService.buy(rpcType, rId, pId, number);
}
}

@ -19,10 +19,12 @@ package com.alibaba.cloud.example.frontend.controller;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import com.alibaba.cloud.example.common.Constants;
import com.alibaba.cloud.example.common.RPCType;
import com.alibaba.cloud.example.common.entity.Product;
import com.alibaba.cloud.example.common.entity.ResultHolder;
@ -103,12 +105,26 @@ public class FrontController {
@GetMapping("/listProduct")
public String listProduct(
@CookieValue(value = "rpc_type", required = false,
defaultValue = "Dubbo") RPCType rpcType,
@RequestParam(required = false, defaultValue = "feign") String call,
defaultValue = "SpringCloud") RPCType rpcType,
@RequestParam(required = false, defaultValue = Constants.FEIGN) String call,
Model model) {
// normal
ResultHolder<List<Product>> resultHolder = (call.equals("feign")
? productDAO.list() : productDAO.listTemplate());
ResultHolder<List<Product>> resultHolder;
// Determine the method of the request
switch (call) {
case Constants.FEIGN:
resultHolder = productDAO.list();
break;
case Constants.REST_TEMPLATE:
resultHolder = productDAO.listByRestTemplate();
break;
case Constants.WEB_CLIENT:
resultHolder = productDAO.listByWebClient();
break;
default:
throw new IllegalArgumentException("The web request is malformed.");
}
model.addAttribute("result", JSON.toJSONString(resultHolder.getResult()));
model.addAttribute("products", resultHolder.getResult());
@ -120,10 +136,10 @@ public class FrontController {
@GetMapping("/detailProduct")
public String detailProduct(
@CookieValue(value = "rpc_type", required = false,
defaultValue = "Dubbo") RPCType rpcType,
defaultValue = "SpringCloud") RPCType rpcType,
@RequestParam(required = false, defaultValue = "12") String id,
@RequestParam(required = false, defaultValue = "false") Boolean hidden,
@RequestParam(required = false, defaultValue = "feign") String call,
@RequestParam(required = false, defaultValue = Constants.FEIGN) String call,
Model model) {
// unit
ResultHolder<Product> resultHolder = getProductResultHolder(rpcType, id, hidden,
@ -138,21 +154,39 @@ public class FrontController {
private ResultHolder<Product> getProductResultHolder(RPCType rpcType, String id,
Boolean hidden, String call) {
// normal
ResultHolder<Product> resultHolder;
resultHolder = hidden ? productDAO.detailHidden(id)
: (call.equals("feign")
? productDAO.detail(AppContextClient.getRouteId(), id)
: productDAO.detailTemplate(AppContextClient.getRouteId(), id));
if (Objects.equals(hidden, true)) {
return productDAO.detailHidden(id);
}
// Determine the method of the request
switch (call) {
case Constants.FEIGN:
resultHolder = productDAO.detail(AppContextClient.getRouteId(), id);
break;
case Constants.REST_TEMPLATE:
resultHolder = productDAO.detailByRestTemplate(AppContextClient.getRouteId(), id);
break;
case Constants.WEB_CLIENT:
resultHolder = productDAO.detailByWebClient(AppContextClient.getRouteId(), id);
break;
default:
throw new IllegalArgumentException("The web request is malformed.");
}
return resultHolder;
}
@RequestMapping("/buyProduct")
public String buyProduct(
@CookieValue(value = "rpc_type", required = false,
defaultValue = "Dubbo") RPCType rpcType,
defaultValue = "SpringCloud") RPCType rpcType,
@RequestParam(required = false, defaultValue = "12") String pId,
@RequestParam(required = false, defaultValue = "1") Integer number,
@RequestParam(required = false, defaultValue = "feign") String call,
@RequestParam(required = false, defaultValue = Constants.FEIGN) String call,
Model model) {
// unit
ResultHolder<String> resultHolder = productDAO.buy(AppContextClient.getRouteId(),

@ -78,7 +78,6 @@
- `appactive.dataId.trafficRouteRulePath`: 描述路由标和单元的映射关系
- `appactive.dataId.dataScopeRuleDirectoryPath_mysql-product`: 描述数据库的属性
2. 启动 5 套应用,启动参数分别为:
- frontend
@ -132,9 +131,9 @@
![](../../spring-cloud-alibaba-docs/src/main/asciidoc-zh/pic/image-2022-09-15-16-16-25-989.png)
由于上述路径中的 `/listProduct` 在 product 应用中匹配到的是 `/*` 路径规则,根据规则内容,该服务属于普通应用做了未做单元化拆分所以frontend 在从注册中心获取的 product 地址列表中不存在倾向性,会随机选择地址进行请求发送。因此多次请求上述路径,会看到请求在 product 的一般Unit)和 中心center单元应用中来回切换。
由于上述路径中的 `/listProduct` 在 product 应用中匹配到的是 `/*` 路径规则根据规则内容该服务属于普通应用未做单元化拆分所以frontend 在从注册中心获取的 product 地址列表中不存在倾向性,会随机选择地址进行请求发送。因此多次请求上述路径,会看到请求在 product 的一般Unit)和 中心center单元应用中来回切换。
2. 归属于 unit 单元的核心应用服务调用演示。在浏览器中输入:`http://127.0.0.1:8079/detailProduct` 路径,由于上述路径中的 `/detailProduct` 在 product 应用中匹配到的是 `/detail/*` 路径规则,根据规则内容,该服务属于核心应用做了单元拆分,其会根据请求中 Header, Cookie 或请求参数中的变量具体的值去判断该请求的下游单元类型,由于事先配置如下切流规则(具体可见 rule 目录下的 idUnitMapping.json 文件内容):
2. 归属于 unit 单元的核心应用服务调用演示。在浏览器中输入:`http://127.0.0.1:8079/detailProduct` 路径,由于上述路径中的 `/detailProduct` 在 product 应用中匹配到的是 `/detail/*` 路径规则,根据规则内容,该服务属于核心应用做了单元拆分,其会根据请求中 Header, Cookie 或请求参数中的变量具体的值去判断该请求的下游单元类型,由于事先配置如下切流规则(具体可见 rule 目录下的 idUnitMapping.json 文件内容):
```
{
"itemType": "UnitRuleItem",
@ -171,7 +170,7 @@
![](../../spring-cloud-alibaba-docs/src/main/asciidoc-zh/pic/image-2022-09-15-16-14-50-461.png)
3. 归属于中心Center单元的全局应用服务调用演示。在浏览器中输入`http://127.0.0.1:8079/buyProduct` 路径,由于上述路径中的 `/buyProduct` 在 product 和 storage 应用中匹配到的是 `/buy/*` 路径规则根据规则内容该服务属于全局应用未做单元会拆分其会直接将请求发送到下游的中心Center单元中全局应用实例。
3. 归属于中心Center单元的全局应用服务调用演示。在浏览器中输入`http://127.0.0.1:8875/buyProduct` 路径,由于上述路径中的 `/buyProduct` 在 product 和 storage 应用中匹配到的是 `/buy/*` 路径规则根据规则内容该服务属于全局应用未做单元会拆分其会直接将请求发送到下游的中心Center单元中全局应用实例。
![](../../spring-cloud-alibaba-docs/src/main/asciidoc-zh/pic/image-2022-09-15-16-14-02-388.png)
@ -179,7 +178,7 @@
- 构建新的映射关系规则和禁写规则(手动)
- 将禁写规则推送给应用
- 等待数据追平后将新的映射关系规则推送给应用
接下来演示的切流规则会将用户Id为 0 ~ 2999 的请求将发送给下游提供者中的一般Unit单元中的核心应用实例用户Id为 3000 ~ 9999 的请求将发送给下游提供者中的中心Center单元中的全局应用实例。具体的规则详情见 idUnitMappingNext.json
接下来演示的切流规则会将用户Id为 0 ~ 2999 的请求将发送给下游提供者中的一般Unit单元中的核心应用实例用户Id为 3000 ~ 9999 的请求将发送给下游提供者中的中心Center单元中的全局应用实例。具体的规则详情见 idUnitMappingNext.json
```
{
"itemType": "UnitRuleItem",
@ -215,4 +214,3 @@

Loading…
Cancel
Save