接下来在整个微服务架构中,咱们比较关心的就是服务间的服务改如何调用,有哪些调用方式?java
总结:
在springcloud中服务间调用方式主要是使用 http restful方式进行服务间调用
git
在上面的基础上,使用的是consul注册,pom.xml文件github
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.md</groupId> <artifactId>04-products9998</artifactId> <version>0.0.1-SNAPSHOT</version> <name>04-products9998</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Hoxton.SR6</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--引入consul依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency> <!-- 这个包是用作健康度监控的--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies> <!--全局管理springcloud版本,并不会引入具体依赖--> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
@RestController @Slf4j public class ProductController { @Value("${server.port}") private int port; @GetMapping("/product/findAll") public Map<String,Object> findAll(){ log.info("商品服务查询全部调用成功,当前服务端口:[{}]",port); Map<String, Object> map = new HashMap<String,Object>(); map.put("msg","服务调用成功,服务提供端口为: "+port); map.put("status",true); return map; } }
@RestController @Slf4j public class UserController { @GetMapping("/user/findAll") public String findAll(){ log.info("调用用户服务..."); //1. 使用restTemplate调用商品服务 RestTemplate restTemplate = new RestTemplate(); // get请求getxxx,post请求postxxx // 参数1:请求路径,参数2:返回的类型是String的 String forObject = restTemplate.getForObject("http://localhost:9998/product/findAll", String.class); return forObject; } }
再建立一个服务类,和上面的服务类同样,只有端口不一样web
server.port=9997 spring.application.name=products spring.cloud.consul.port=8500 spring.cloud.consul.host=localhost
其余同样算法
@RestController @Slf4j public class ProductController { @Value("${server.port}") private int port; @GetMapping("/product/findAll") public Map<String,Object> findAll(){ log.info("商品服务查询全部调用成功,当前服务端口:[{}]",port); Map<String, Object> map = new HashMap<String,Object>(); map.put("msg","服务调用成功,服务提供端口为: "+port); map.put("status",true); return map; } }
# 1.项目中引入依赖 - 说明: 1.若是使用的是eureka client 和 consul client,无须引入依赖,由于在eureka,consul中默认集成了ribbon组件 2.若是使用的client中没有ribbon依赖须要显式引入以下依赖
<!--引入ribbon依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency>
# 2.查看consul client中依赖的ribbon
# 3.使用restTemplate + ribbon进行服务调用 - 使用discovery client 进行客户端调用 - 使用loadBalanceClient 进行客户端调用 - 使用@loadBalanced 进行客户端调用
# 3.1 使用discovery Client形式调用
@Autowired private DiscoveryClient discoveryClient; //获取服务列表,返回所有的,服务id,上面的products List<ServiceInstance> products = discoveryClient.getInstances("服务ID"); for (ServiceInstance product : products) { log.info("服务主机:[{}]",product.getHost()); log.info("服务端口:[{}]",product.getPort()); log.info("服务地址:[{}]",product.getUri()); log.info("===================================="); }
# 3.2 使用loadBalance Client形式调用
@Autowired private LoadBalancerClient loadBalancerClient; //根据负载均衡策略选取某一个服务调用,服务id=products ServiceInstance product = loadBalancerClient.choose("服务ID");//地址 默认轮询策略 log.info("服务主机:[{}]",product.getHost()); log.info("服务端口:[{}]",product.getPort()); log.info("服务地址:[{}]",product.getUri());
# 3.3 使用@loadBalanced(经常使用)
//1.整合restTemplate + ribbon @Configuration public class RestTemplateConfig { // 在工厂中建立一个restTemplate对象 @Bean // 加上这个注解表明当前的restTemplate对象带有ribbon负载均衡 @LoadBalanced public RestTemplate getRestTemplate(){ return new RestTemplate(); } } //2.调用controller服务位置注入RestTemplate // 此时的restTemplate就具备了负载均衡的功能 @Autowired private RestTemplate restTemplate; //3.调用 @RestController @Slf4j public class UserController { @Autowired private RestTemplate restTemplate; @GetMapping("/user/findAll") public String findAll(){ // 服务id就是在配置文件中的当前服务名products String forObject = restTemplate.getForObject("http://服务ID/product/findAll", String.class); return forObject; } }
默认的轮训策略,也就是当前访问的9998,以后是9997,循环访问spring
ribbon负载均衡算法apache
RoundRobinRule 轮训策略 按顺序循环选择 Server浏览器
RandomRule 随机策略 随机选择 Serverrestful
AvailabilityFilteringRule 可用过滤策略
`会先过滤因为屡次访问故障而处于断路器跳闸状态的服务,还有并发的链接数量超过阈值的服务,而后对剩余的服务列表按照轮询策略进行访问markdown
WeightedResponseTimeRule 响应时间加权策略
`根据平均响应的时间计算全部服务的权重,响应时间越快服务权重越大被选中的几率越高,刚启动时若是统计信息不足,则使用RoundRobinRule策略,等统计信息足够会切换到
RetryRule 重试策略
`先按照RoundRobinRule的策略获取服务,若是获取失败则在制定时间内进行重试,获取可用的服务。
BestAviableRule 最低并发策略
`会先过滤掉因为屡次访问故障而处于断路器跳闸状态的服务,而后选择一个并发量最小的服务
# 1.修改服务默认随机策略 - 服务id.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule `下面的products为服务的惟一标识
products.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
# 1.官方中止维护说明 - https://github.com/Netflix/ribbon