SpringCloud 商城系统搭建之Ribbon (基于Ribbon + RestTemplate)分析

你猜 阅读:245 2021-03-31 13:18:57 评论:0

Spring Cloud 服务调用方式

Spring Cloud有两种服务调用方式,一种是Ribbon + RestTemplate,另一种是feign。在这一篇文章首先讲解下基于Ribbon + RestTemplate。

Ribbon简介

Ribbon在Spring Cloud中担任着负载均衡的角色,它是一个基于HTTP和TCP的客户端负载均衡工具。Spring Cloud Ribbon只是一个工具类框架,它可以独立部署但是也不需要独立部署,它几乎存在于所有springcloud 构建的微服务和基础设施中。

Ribbon已经实现了负载均衡对象:

/** 
* 
* RoundRobinRule 轮询 
* RandomRule 随机 
* AvailabilityFilteringRule 优先过滤因访问故障处于断路器跳闸的服务 
* 以及并发连接数超过阈值的服务。然后对剩余的服务做轮询 
* 
* WeightedResponseTimeRule 根据平均响应时间计算所有服务的权重,响应时间越快的权重越大 
* 选择几率越高。 
* 
* RetryRule 先按照轮询获取服务,如果获取服务失败, 
* 在规定时间内会重试获取可用的服务 
* 
* BestAvailableRule 优先过滤因访问故障处于断路器跳闸的服务, 
* 然后选择并发量最小的服务 
* 
* ZoneAvoidanceRule 默认规则,复合判断服务所在区域的性能,和服务的可用性选择服务器 
* 
*/

前提

本文是基于SpringCloud 商城系统搭建之eureka 

Ribbon集成

1、在supermarker-consume的RestTemplate对象上加上 @LoadBalanced注解 和实列化负载均衡策略

代码修改如下:

package com.zzg.config; 
 
import org.springframework.cloud.client.loadbalancer.LoadBalanced; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.web.client.RestTemplate; 
 
import com.netflix.loadbalancer.IRule; 
import com.netflix.loadbalancer.RandomRule; 
 
@Configuration 
public class RestConfig { 
	@Bean 
	@LoadBalanced //负载均衡标识 
    public RestTemplate restTemplate(){ 
        return new RestTemplate(); 
    } 
	 
	@Bean // 负载均衡策略实列化 
	public IRule getIRule(){ 
		// 负载均衡:随机策略 
		return new RandomRule(); 
	} 
} 

2、创建两个生产者:supermarker-provider 和supermarker-provider-second

两个生产者的application.properties 大致如下:

server.port=8082 
# 生产者应用名称 - 
spring.application.name=provider 
# 生产者实例名,同一个spring.application.name 名称唯一 
eureka.instance.instance-id=provider1 
         
eureka.client.register-with-eureka=true 
# 和eureka服务器通讯的URL 
eureka.client.service-url.defaultZone=http://localhost:8081/eureka/ 
 
# 设置心跳的时间间隔(默认是30秒) 
eureka.instance.lease-renewal-interval-in-seconds=5 
# eureka server 最后一次收到心跳时等待的时间,超时将会移除client(默认是90秒) 
eureka.instance.lease-expiration-duration-in-seconds=3 
 
 
#h2配置 
#启用SQL语句的日志记录 
spring.jpa.show-sql=true 
#设置ddl模式 
spring.jpa.hibernate.ddl-auto=update 
##数据库连接设置 
#配置h2数据库的连接地址 
spring.datasource.url=jdbc:h2:mem:dbtest 
spring.datasource.username=sa 
spring.datasource.password=sa 
spring.datasource.driverClassName=org.h2.Driver 
##数据初始化设置 
#进行该配置后,每次启动程序,程序都会运行resources/db/schema.sql文件,对数据库的结构进行操作。 
spring.datasource.schema=classpath:db/schema.sql 
#进行该配置后,每次启动程序,程序都会运行resources/db/data.sql文件,对数据库的数据操作。 
spring.datasource.data=classpath:db/data.sql 
##h2 web console设置 
#表明使用的数据库平台是h2 
spring.datasource.platform=h2 
# 进行该配置后,h2 web consloe就可以在远程访问了。否则只能在本机访问。 
spring.h2.console.settings.web-allow-others=true 
#进行该配置,你就可以通过YOUR_URL/h2访问h2 web consloe。YOUR_URL是你程序的访问URl。 
spring.h2.console.path=/h2 
#进行该配置,程序开启时就会启动h2 web consloe。当然这是默认的,如果你不想在启动程序时启动h2 web consloe,那么就设置为false。 
spring.h2.console.enabled=true 
 
#spring-boot-actuator配置 
#开放所有的web Endpoints 
management.endpoints.web.exposure.include=*

注意:两个消费者除端口和实例id外其他都是一样的,这里就不再粘贴其他功能代码

3、修改两个生产者:supermarker-provider 和supermarker-provider-second 对外提供的接口

supermarker-provider

package com.zzg.controller; 
 
import java.util.ArrayList; 
import java.util.List; 
 
import javax.persistence.criteria.CriteriaBuilder; 
import javax.persistence.criteria.CriteriaQuery; 
import javax.persistence.criteria.Predicate; 
import javax.persistence.criteria.Root; 
 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.beans.factory.annotation.Value; 
import org.springframework.data.jpa.domain.Specification; 
import org.springframework.web.bind.annotation.GetMapping; 
import org.springframework.web.bind.annotation.PathVariable; 
import org.springframework.web.bind.annotation.RestController; 
 
import com.zzg.dao.UserRepository; 
import com.zzg.entity.User; 
 
@RestController 
public class UserController { 
	@Autowired 
	private UserRepository userRepository; 
	 
	 
	@Value("${server.port}") 
	private int port; 
	 
	@GetMapping("/user/{id}") 
    public User findById(@PathVariable Integer id) { 
		System.out.println("---------------provider端口被调用--------------" + port); 
		 
        return userRepository.findOne(new Specification<User>() { 
			 
			@Override 
			public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) { 
				// TODO Auto-generated method stub 
				 List<Predicate> predicates = new ArrayList<Predicate>(); 
	             // 用户编号 
	             predicates.add(criteriaBuilder.equal(root.<Integer> get("useId"), id)); 
	                 
				return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction(); 
			} 
		}).orElse(null); 
    } 
 
} 

supermarker-provider-second

package com.zzg.controller; 
 
import java.util.ArrayList; 
import java.util.List; 
 
import javax.persistence.criteria.CriteriaBuilder; 
import javax.persistence.criteria.CriteriaQuery; 
import javax.persistence.criteria.Predicate; 
import javax.persistence.criteria.Root; 
 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.beans.factory.annotation.Value; 
import org.springframework.data.jpa.domain.Specification; 
import org.springframework.web.bind.annotation.GetMapping; 
import org.springframework.web.bind.annotation.PathVariable; 
import org.springframework.web.bind.annotation.RestController; 
 
import com.zzg.dao.UserRepository; 
import com.zzg.entity.User; 
 
@RestController 
public class UserController { 
	@Autowired 
	private UserRepository userRepository; 
	 
	@Value("${server.port}") 
	private int port; 
	 
	@GetMapping("/user/{id}") 
    public User findById(@PathVariable Integer id) { 
		System.out.println("---------------provider-second端口被调用--------------" + port); 
		 
        return userRepository.findOne(new Specification<User>() { 
			 
			@Override 
			public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) { 
				// TODO Auto-generated method stub 
				 List<Predicate> predicates = new ArrayList<Predicate>(); 
	             // 用户编号 
	             predicates.add(criteriaBuilder.equal(root.<Integer> get("useId"), id)); 
	                 
				return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction(); 
			} 
		}).orElse(null); 
    } 
 
} 

Ribbon 负载均衡功能测试

1、分别启动supermarker-eureka、二个生产者(supermarker-provider和supermarker-provider-second)和消费者(supermarker-consume)
supermarker-eureka启动后,看到如下界面证明二个生产者创建成功,会显示有二个生产者,左边红框内是生产者集群名称,消费者在通过IP和port调用生产者接口时都是通过集群名称调用的,右边红框是实例名称

2、通过消费者调用生产者

消费者调用生产者代码

package com.zzg.controller; 
 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.web.bind.annotation.GetMapping; 
import org.springframework.web.bind.annotation.PathVariable; 
import org.springframework.web.bind.annotation.RestController; 
import org.springframework.web.client.RestTemplate; 
 
import com.zzg.entity.User; 
 
@RestController 
public class UserController { 
	@Autowired 
	private RestTemplate restTemplate; 
	 
	@GetMapping("/user/{id}") 
    public User findById(@PathVariable Integer id) { 
		return restTemplate.getForObject("http://provider/user/" + id, User.class); 
	} 
 
} 

消费者启动成功后,通过浏览器访问:http://localhost:8083/user/1 发现两个生产者控制台输入如下信息截图:

 

 

说明基于:Ribbon + RestTemplate 负载均衡功能完结,

温馨提示:Ribbon默认采用的负载均衡策略是轮询

声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

发表评论
搜索
KIKK导航

KIKK导航

排行榜
关注我们

一个IT知识分享的公众号