【SpringCloud】02 搭建springcloud微服务项目,服务治理组件nacos,负载均衡ribbon,远程调用Openfeign
创始人
2024-02-07 05:15:21
0

文章目录

  • 搭建springcloud微服务项目
    • 1. 微服务父工程
    • 2. 创建子模块-shop-common
    • 3. 创建子模块--shop-product
    • 4. 创建子模块--shop-order
  • 服务治理组件
    • 1. 如何使用nacos
    • 2. 微服务客户端连接到nacos注册中心
    • 3. 消费端如何通过nacos调用提供者
  • 负载均衡
    • 1. 自己控制负载均衡
    • 2. ribbon完成负载均衡
      • 2.1 如何使用ribbon
      • 2.2 自定义负载均衡策略
  • 远程调用组件-Openfeign
    • 1. 概述
    • 2. 如何使用openfeign组件

搭建springcloud微服务项目

技术栈:

  1. springcloud-alibaba
  2. mybatis-plus 持久性框架
  3. mysql数据库5.7以上
  4. springboot来搭建每个微服务。

1. 微服务父工程

在这里插入图片描述
把其他的全删掉,只保留一个pom文件


4.0.0org.springframework.bootspring-boot-starter-parent2.3.12.RELEASE com.aaaqy156-shop-parent0.0.1-SNAPSHOTpomqy156-shop-parentDemo project for Spring Boot1.8UTF-8UTF- 8Hoxton.SR82.2.3.RELEASEorg.springframework.cloudspring-cloud-dependencies${spring-cloud.version}pomimportcom.alibaba.cloudspring-cloud-alibaba-dependencies${spring-cloud-alibaba.version}pomimportorg.springframework.bootspring-boot-maven-plugin

2. 创建子模块-shop-common

把其他模块公共得代码放入到该模块。- - -实体 工具类

在这里插入图片描述

  org.projectlomboklombokcom.baomidoumybatis-plus-boot-starter3.5.0

定义相关得实体类

@Data
@TableName(value = "shop_order")
public class Order {//订单id@TableIdprivate Long oid;//用户idprivate Integer uid;//用户名private String username;//商品id---购买时99---->活动结束后199private Long pid;//商品得名称private String pname;//商品得价格private Double pprice;//购买得数量private Integer number;
}@Data
@TableName("shop_product")
public class Product {@TableIdprivate Long pid;private String pname;private Double pprice;private Integer stock;
}

3. 创建子模块–shop-product

关于商品表操作的接口
在这里插入图片描述

	com.aaashop-common0.0.1-SNAPSHOTorg.springframework.bootspring-boot-starter-webmysqlmysql-connector-java

配置文件

# 定义端口号 [8001~8009 未来方便搭建集群]
server:port: 8001#数据源得信息
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/springcloud?serverTimezone=Asia/Shanghaiusername: rootpassword: root# mybatis打印日志
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

dao接口

/*** @program: qy156-shop-parent* @description:* @author: 闫克起* @create: 2022-11-17 16:22**/
public interface ProductDao extends BaseMapper {
}

service代码

@Service
public class ProductService implements IProductService {@Autowiredprivate ProductDao productDao;@Overridepublic Product findById(Long pid) {return productDao.selectById(pid);}
}

controller

@RestController
@RequestMapping("product")
public class ProductController {@Autowiredprivate IProductService productService;@GetMapping("/getById/{pid}")public Product getById(@PathVariable Long pid){return productService.findById(pid);}
}

主启动类

@SpringBootApplication
@MapperScan(basePackages = "com.aaa.product.dao")
public class ProductApp {public static void main(String[] args) {SpringApplication.run(ProductApp.class,args);}
}

在这里插入图片描述

4. 创建子模块–shop-order

关于订单表得所有操作接口
在这里插入图片描述

	com.aaashop-common0.0.1-SNAPSHOTorg.springframework.bootspring-boot-starter-webmysqlmysql-connector-java

配置

#端口号---[9001~9009]集群模式
server:port: 9001#数据源得信息
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/springcloud?serverTimezone=Asia/Shanghaiusername: rootpassword: root
# sql显示在控制台
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

dao接口

package com.aaa.order.dao;import com.baomidou.mybatisplus.core.mapper.BaseMapper;/*** @program: qy156-shop-parent* @description:* @author: 闫克起* @create: 2022-11-18 14:34**/
public interface OrderDao extends BaseMapper {}

service代码

@Service
public class OrderService implements IOrderService {@Autowiredprivate OrderDao orderDao;@Overridepublic int save(Order order) {return orderDao.insert(order);}
}

配置类中注入restTemplate

@SpringBootApplication
public class AppOrder {public static void main(String[] args) {SpringApplication.run(AppOrder.class, args);}@Beanpublic RestTemplate restTemplate(){return new RestTemplate();}
}

controller代码

package com.aaa.order.controller;import com.aaa.entity.Order;
import com.aaa.entity.Product;
import com.aaa.order.service.IOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;/*** @program: qy156-shop-parent* @description:* @author: 闫克起2* @create: 2022-11-17 16:33**/
@RestController
@RequestMapping("/order")
public class OrderController {//必须创建并交于spring容器管理。这样才能被注入到相应的类属性上@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate IOrderService orderService;@GetMapping("/saveOrder")public String saveOrder(Long pid,Integer num){Order order=new Order();//用户得信息可以从登录后获取--Session  redis  jwtorder.setUid(1);order.setUsername("张成");//为订单对象设置商品得信息order.setPid(pid);//需要远程调用商品微服务中的指定接口[注意:凡是关于商品的操作都有商品微服务来执行。]//远程调用的方式:第一种基于TCP协议的RPC远程调用   第二种基于http协议Restful风格的调用。//分布式架构:TCP协议的//微服务架构:http协议的。---在spring框架中封装了一个工具RestTemplate。 如果不是使用的spring框架。你需要自己封装HttpClient工具Product product = restTemplate.getForObject("http://localhost:8001/product/getById/"+pid, Product.class);order.setPname(product.getPname());order.setPprice(product.getPprice());order.setNumber(num);orderService.save(order);return "下单成功";}
}

思考: 上面我们写远程调用代码 是否存在缺陷?


[1] 我们把商品微服务地址写死在自己代码中 硬编码—如果商品微服务地址发生改变。需要修改我们自己当前微服务的代码


[2] 如果商品微服务 搭建了集群模式。 订单微服务这边如何调用相应的商品微服务从而达到负载均衡的特性。

服务器治理组件。

eureka:当作服务治理组件。---->netflix公司的产品—停止更新维护


zookeeper: 服务治理组件。---->dubbo分布式框架配合


nacos: 服务治理组件。---->阿里巴巴的产品。

这里使用nacos

服务治理组件

在这里插入图片描述

1. 如何使用nacos

https://github.com/alibaba/nacos/releases

nacos1.3以后支持了集群模式。1.3以前不支持。

安装nacos服务端。
必须安装jdk并配置环境变量。而且不能把nacos放入中文目录

在这里插入图片描述
bin目录下startup.cmd启动nacos
在这里插入图片描述
访问nacos服务器
在这里插入图片描述
在这里插入图片描述

2. 微服务客户端连接到nacos注册中心

(1)引入依赖


com.alibaba.cloudspring-cloud-starter-alibaba-nacos-discovery

(2)修改配置文件
在这里插入图片描述

测试:
在这里插入图片描述

3. 消费端如何通过nacos调用提供者

引入nacos依赖和配置nacos地址
修改控制层代码

package com.aaa.order.controller;import com.aaa.entity.Order;
import com.aaa.entity.Product;
import com.aaa.order.service.IOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;import java.util.List;/*** @program: qy156-shop-parent* @description:* @author: 闫克起2* @create: 2022-11-17 16:33**/
@RestController
@RequestMapping("/order")
public class OrderController {//必须创建并交于spring容器管理。这样才能被注入到相应的类属性上@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate IOrderService orderService;//在nacos中封装了一个类DiscoveryClient,该类可以获取注册中心中指定的清单列表。@Autowiredprivate DiscoveryClient discoveryClient;@GetMapping("/saveOrder")public String saveOrder(Long pid,Integer num){Order order=new Order();//用户得信息可以从登录后获取--Session  redis  jwtorder.setUid(1);order.setUsername("张成");//为订单对象设置商品得信息order.setPid(pid);//获取指定的实例List instances = discoveryClient.getInstances("shop-product");ServiceInstance serviceInstance = instances.get(0);
//        String path = serviceInstance.getHost().toString();
//        System.out.println(path+"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
//        Integer port = serviceInstance.getPort();
//        System.out.println(port+"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");String uri = serviceInstance.getUri().toString();
//        System.out.println(uri+"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");Product product = restTemplate.getForObject(uri+"/product/getById/"+pid, Product.class);order.setPname(product.getPname());order.setPprice(product.getPprice());order.setNumber(num);orderService.save(order);return "下单成功";}
}

如果后期 提供者的地址发生改变,也不影响消费者的代码。

思考: 上面使用从nacos拉取服务清单的模式是否存在问题?
没有实现负载均衡的问题。如果后期商品微服务在部署时 是一个集群。调用者应该把请求均摊到每个服务器上。

负载均衡

通俗的讲, 负载均衡就是将负载(工作任务,访问请求)进行分摊到多个操作单元(服务器,组件)上进行执行。

模拟搭建多个商品微服务。
在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

1. 自己控制负载均衡

人为的完成订单微服务调用商品微服务负载均衡的特性。

package com.aaa.order.controller;import com.aaa.entity.Order;
import com.aaa.entity.Product;
import com.aaa.order.service.IOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;import java.util.List;
import java.util.Random;/*** @program: qy156-shop-parent* @description:* @author: 闫克起2* @create: 2022-11-17 16:33**/
@RestController
@RequestMapping("/order")
public class OrderController {//必须创建并交于spring容器管理。这样才能被注入到相应的类属性上@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate IOrderService orderService;@Autowiredprivate DiscoveryClient discoveryClient;@GetMapping("/saveOrder")public String saveOrder(Long pid,Integer num){Order order=new Order();//用户得信息可以从登录后获取--Session  redis  jwtorder.setUid(1);order.setUsername("张成");//为订单对象设置商品得信息order.setPid(pid);//在nacos中封装了一个类DiscoveryClient,该类可以获取注册中心中指定的清单列表。//获取指定的实例List instances = discoveryClient.getInstances("shop-product");//随机产生一个下标--0~sizeint index = new Random().nextInt(instances.size());ServiceInstance serviceInstance = instances.get(index);String uri = serviceInstance.getUri().toString();Product product = restTemplate.getForObject(uri+"/product/getById/"+pid, Product.class);order.setPname(product.getPname());order.setPprice(product.getPprice());order.setNumber(num);orderService.save(order);return "下单成功";}
}

这两行是控制使用哪个微服务

//随机产生一个下标--0~size
int index = new Random().nextInt(instances.size());
ServiceInstance serviceInstance = instances.get(index);

如果想改变负载均衡的策略,例如想变成轮询策略,就需要来这里修改源代码,硬编码问题【开闭原则】

提供了ribbon组件—该组件可以完成负载均衡。

2. ribbon完成负载均衡

ribbon是 Netflix 发布的一个负载均衡器,有助于控制 HTTP 和 TCP客户端行为。在 SpringCloud 中,nacos一般配合Ribbon进行使用,Ribbon提供了客户端负载均衡的功能,Ribbon利用从nacos中读取到的服务信息,在调用服务节点提供的服务时,会合理(策略)的进行负载。

在SpringCloud中可以将注册中心和Ribbon配合使用,Ribbon自动的从注册中心中获取服务提供者的列表信息,并基于内置的负载均衡算法,请求服务。

Ribbon自动的从注册中心中获取服务提供者的 列表信息,并基于内置的负载均衡算法,请求服务

2.1 如何使用ribbon

不需要再引入任何依赖
在这里插入图片描述
只需要再RestTemplate获取的bean上添加一个LoadBalance注解
在这里插入图片描述

@LoadBalanced是告诉RestTemplate使用ribbon完成负载均衡。自动从注册中心拉取服务。使用内置的负载均衡策略完成服务的调用。

修改controller代码
在这里插入图片描述
测试发现默认使用的是轮询策略。ribbon是否可以改变为其他策略。而ribbon中提供了很多策略。

策路名策略描述实现说明
BestAvailableRule选择─个最小的并发请求的server逐个考察Server,如果Server被tripped了,则忽略,在选择其中ActiveRequestsCount最小的server
RandomRule随机选择一个server在index上随机。选择index对应位置的server
RoundRobinRule轮询方式轮询选择轮询index,选择index对应位置的server
AvailabilityFilteringRule过滤掉那些因为一直连接失败的被标记为circuittripped的后端server ,并过滤掉那些高并发的的后端server (active connections超过配置的阈值)使用一个AvailabilityPredicate来包含过滤server的逻辑,其实就就是检查status里记录的各个server的运行状态
WeightedResponseTimeRule根据相应时间分配一个weight,相应时间越长,weight越小,被选中的可能性越低。一个后台线程定期的从status里面读取评价响应时间,为每个server计算一个weight。Weight的计算也比较简单responsetime减去每个server自己平均的responsetime是server的权重。当刚开始运行,没有形成statas时,使用roubine策略选择server。
RetryRule对选定的负载均衡策略机上重试机制。在一个配置时间段内当选择server不成功,则—直尝试使用subRule的方式选择一个可用的server
ZoneAvoidanceRule复合判断server所在区域的性能和server的可用性选择server使用ZoneAvoidancePredicate和AvailabilityPredicate来判断是否选择某个server,前—个判断判定一个zone的运行性能是否可用,别除不可用的zone (的所有server) , AvailabilityPredicate用于过滤掉连接数过多的Server。

如何使用相应的策略:

shop-product:  # 这里使用服务的名称ribbon:NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #使用的的负载均衡策略

如果上面的策略不够用,你也可以自定义策略类。实现IRule接口完成自定义策略。
在这里插入图片描述
如果上面的策略不够用,你也可以自定义策略类。实现IRule接口完成自定义策略。

2.2 自定义负载均衡策略

不管任何一个负载均衡,都是IRule接口的子类。
在这里插入图片描述
我们自定义的规则类 也必须继承AbastractLoadBalancerRule类。

需求:
要求自定义的算法:依旧是轮询策略,但是每个服务器被调用5次后轮到下一个服务,即以前是每个服务被调用1次,现在是每个被调用5次 .

自定义规则类—模拟原来有的类。

package com.aaa.order.rule;import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancer;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;import java.util.List;/*** @program: qy156-shop-parent* @description:* @author: 闫克起2* @create: 2022-11-19 14:42**/
public class MyRule extends AbstractLoadBalancerRule {@Overridepublic void initWithNiwsConfig(IClientConfig iClientConfig) {//初始化方法 读取配置文件内容}//统计访问的次数private int total;//作为集群服务器下标private int index;@Overridepublic Server choose(Object key) {//获取负载均衡选择器ILoadBalancer lb = getLoadBalancer();if (lb == null) {return null;}Server server = null;while (server == null) {if (Thread.interrupted()) {return null;}//获取所有可用的服务器List upList = lb.getReachableServers();//获取所有的服务器。List allList = lb.getAllServers();int serverCount = allList.size();if (serverCount == 0) {return null;}//判断该服务访问的次数是否>5次if(total<5){server=upList.get(index);total++;}else{total=0;index++;index=index%upList.size();}if (server == null) {Thread.yield();continue;}if (server.isAlive()) {return (server);}// Shouldn't actually happen.. but must be transient or a bug.server = null;Thread.yield();}return server;}
}

(2)创建一个配置类,该类用于创建上面的bean对象

@Configuration
public class RuleConfig {@Beanpublic MyRule myRule(){return new MyRule();}
}

(3)ribbon使用上面自定义的规则
在这里插入图片描述

远程调用组件-Openfeign

我们上面服务与服务之间的调用,使用的为RestTemplate工具类,来完成相应的调用。但是RestTemplate这种模式不符合我们编程的习惯。

dao----service----controller:在service类中注入dao对象,然后调用dao中的方法,并传入相关的参数,以及接受相关的返回类型。

1. 概述

OpenFeign是Spring Cloud提供的一个声明式的伪Http客户端, 它使得调用远程服务就像调用本地服务一样简单, 只需要创建一个接口并添加一个注解即可。

Nacos很好的兼容了OpenFeign, Feign负载均衡默认集成了 Ribbon, 所以在Nacos下使用Fegin默认就实现了负载均衡的效果。

2. 如何使用openfeign组件

(1)引入相关的依赖


org.springframework.cloudspring-cloud-starter-openfeign

(2)创建feign接口

value:调用远程微服务的名称
@FeignClient(value = "shop-product")
public interface ProductFeign {@GetMapping("/product/getById/{pid}")public Product getById(@PathVariable Long pid);
}

(3)开启feign注解的驱动
在这里插入图片描述
(4)使用feign接口

package com.aaa.order.controller;import com.aaa.entity.Order;
import com.aaa.entity.Product;
import com.aaa.order.feign.ProductFeign;
import com.aaa.order.service.IOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;import java.util.List;
import java.util.Random;/*** @program: qy156-shop-parent* @description:* @author: 闫克起2* @create: 2022-11-17 16:33**/
@RestController
@RequestMapping("/order")
public class OrderController {@Autowiredprivate IOrderService orderService;//spring容器会为该接口生成带来实现类。@Autowiredprivate ProductFeign productFeign;@GetMapping("/saveOrder")public String saveOrder(Long pid,Integer num){Order order=new Order();//用户得信息可以从登录后获取--Session  redis  jwtorder.setUid(1);order.setUsername("张恒");//为订单对象设置商品得信息order.setPid(pid);//就像调用本地方法一样Product product = productFeign.getById(pid);order.setPname(product.getPname());order.setPprice(product.getPprice());order.setNumber(num);orderService.save(order);return "成功";}
}

如果nacos单机出现故障,导致所有微服务服务注册和拉取相应的服务信息。从而导致整个项目无法使用。

所以就需要给nacos搭建集群模式
链接:xxx

相关内容

热门资讯

细节决定成败的名言 关于细节决定成败的名言  在日常生活或是工作学习中,大家都经常接触到名言吧,在议论文中,引用名言,不...
表示母爱的格言 表示母爱的格言  慈母爱子,非为报也,表示母爱的格言。以下是关于表示母爱的格言,希望对大家有帮助! ...
大卫·休谟的名言   大卫·休谟(David Hume,1711年4月26日-1776年8月25日下午4点钟)是英格兰...
成功格言:书山有路勤为径,学... 成功格言:书山有路勤为径,学海无涯苦作舟  1、发奋忘食(废寝忘食)  ——《论语·述而》  【记】...
安全教育名言   安全教育名言  1、查隐患及时整改不马虎,纠违章严肃处理不放过。  2、穿马路是左右看,用家电是...
保尔的名言 保尔的名言  1、一个人的生命应当这样度过:当他回首往事的时候不会因虚度年华而悔恨,也不会因碌碌无为...
诚信的名言 有关诚信的名言15篇  在日常的学习、工作、生活中,大家最不陌生的就是名言了吧,名言主要用来激励和告...
环保的名言名句 环保的名言名句  在平平淡淡的日常中,大家总免不了要接触或使用名言吧,在议论文中,引用名言,不但体现...
自强不息的名言名句 自强不息的名言名句  自强不息的名言名句【经典篇】  1、生活的目标,是唯一值得寻找的财富。——史蒂...
教师人生格言大全   教师人生格言大全    1、 教师如果对学生没有热情,决不能成为好教师。但是教师对于学生的爱是一...
简短的人生格言 简短的人生格言集锦55句  人假使没有自尊心,那就会一无价值。——[俄国]屠格涅夫以下是小编为大家推...
谦虚的名言 谦虚的名言  谦虚的名言  在日常学习、工作或生活中,说到名言,大家肯定都不陌生吧,名言可以带来警醒...
珍爱生命的名人名言 珍爱生命的名人名言(精选55句)  关于生命的名人名言有哪些?生命,值得我们尊重,你知道哪些关于生命...
关于知音的名言名句  导语:关于知音或者是友谊的古诗词, 名人名言,这里全都有,关于知音的名言名句。  君子之交淡若水,...
清正廉洁格言 清正廉洁格言最短的人生格言1、执政以廉为本,为官以勤为先。2、做人一身正气,为官一尘不染。3、名位利...
罗素名言 罗素名言69句  1、伟大的事业是根源于坚韧不断的工作,以全付精神去从事,不避艰苦。——罗素  2、...
朋友的名人名言 有关朋友的名人名言汇总  在学习、工作、生活中,大家都不可避免地会接触并使用名言吧,名言可以用来鞭策...
乔布斯名言经典摘抄 乔布斯名言经典摘抄  乔布斯出生于美国加利福尼亚州旧金山,美国发明家、企业家、美国苹果公司联合创办人...
夺眶而出的名言名句 关于夺眶而出的名言名句  这里是郁郁葱葱的山神之森,一定,要有一段时间无法再盼望夏天了,心如刀绞,泪...
信仰名言 精选关于信仰名言  关于信仰名言  1、没有信仰的人如同盲人(弥顿)  2、有信仰未必能成大事,而没...