Nacos注册中心-RestTemplate

3 篇文章 0 订阅
2 篇文章 0 订阅

Nacos注册中心-RestTemplate

在这里插入图片描述

前言

本文主要介绍了创建父子项目,多个模块向Nacos注册中心注册、服务间的远程调用、以及基于Feign实现负载策略

1 项目结构

在这里插入图片描述

fast-common-grpc : GRPC注册模块,如未使用GRPC可忽略此模块

2 模块搭建

2.1 创建父工程

创建一个maven工程,然后在pom.xml文件中添加下面内容

<?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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud-alibaba</artifactId>
        <groupId>com.itsqh</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>shop-common</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.56</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
    </dependencies>
</project>

2.2 创建基础模块

  1. 创建 shop-common 模块,在pom.xml中添加依赖
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud-alibaba</artifactId>
        <groupId>com.itsqh</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>shop-common</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.56</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
    </dependencies>

</project>
  1. 创建实体类
//用户
@Entity(name = "shop_user")//实体类跟数据表的对应
@Data
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)//数据库自增
    private Integer uid;//主键
    private String username;//用户名
    private String password;//密码
    private String telephone;//手机号
}
//商品
@Entity(name = "shop_product")
@Data
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer pid;//主键

    private String pname;//商品名称
    private Double pprice;//商品价格
    private Integer stock;//库存
}
//订单
@Entity(name = "shop_order")
@Data
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long oid;//订单id
    //用户
    private Integer uid;//用户id
    private String username;//用户名
    //商品
    private Integer pid;//商品id
    private String pname;//商品名称
    private Double pprice;//商品单价
    //数量
    private Integer number;//购买数量
}

2.3 创建用户微服务

  1. 新建一个 shop-user 模块,导入依赖
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud-alibaba</artifactId>
        <groupId>com.itsqh</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>shop-user</artifactId>

    <dependencies>
        <!--springboot-web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--shop-common-->
        <dependency>
            <groupId>com.itsqh</groupId>
            <artifactId>shop-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

    </dependencies>
</project>
  1. 编写主类
package com.itsqh;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
 * 
 *@description:  用户服务
 *@author: Shiqinghu
 *@time: 2020/12/2 14:15
 */
@SpringBootApplication
public class UserApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class);
    }
}
  1. 创建配置文件
server:
  port: 8071
spring:
  application:
    name: service-user
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql:///shop?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
    username: root
    password: root
  jpa:
    properties:
      hibernate:
        hbm2ddl:
          auto: update #Springjpa默认创建数据表
        dialect: org.hibernate.dialect.MySQL5InnoDBDialect

2.4 创建商品微服务

  1. 创建一个名为 shop_product 的模块,并添加springboot依赖
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud-alibaba</artifactId>
        <groupId>com.itsqh</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>shop-product</artifactId>
    <dependencies>
        <!--springboot-web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--shop-common-->
        <dependency>
            <groupId>com.itsqh</groupId>
            <artifactId>shop-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>
  1. 编写主类
package com.itsqh;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * 
 *@description:  商品服务
 *@author: Shiqinghu
 *@time: 2020/12/2 14:24
 */
@SpringBootApplication
@EnableDiscoveryClient//开启nacos客户端
public class ProductApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(ProductApplication.class,args);
    }
    
}

  1. 创建配置文件
server:
  port: 8081
spring:
  application:
    name: service-product
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql:///shop?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
    username: root
    password: root
  jpa:
    properties:
      hibernate:
        hbm2ddl:
          auto: update #Springjpa默认创建数据表
        dialect: org.hibernate.dialect.MySQL5InnoDBDialect
  1. 创建ProductDao接口
package com.itsqh.dao;

import com.itsqh.domain.Product;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ProductDao extends JpaRepository<Product, Integer> {
}

  1. 创建ProductService接口和实现类
@Service
public class ProductServiceImpl implements ProductService {

    @Autowired
    private ProductDao productDao;

    /**
     * @description: 根据pid查询商品信息
     * @return: com.itsqh.service.ProductService
     * @author: qinghuShi
     * @time: 2020/12/2 14:50
     *
     */
    @Override
    public Product findByPid(Integer pid) {
        return productDao.findById(pid).get();
    }
}
  1. 创建Controller
@Slf4j
@RestController
public class ProductController {

    @Autowired
    private ProductService productService;

    @RequestMapping("/product/{pid}")
    public Product getProduct(@PathVariable("pid") Integer pid){
        log.info("接下来要进行{}号商品信息的查询", pid);
        Product product = productService.findByPid(pid);
        log.info("商品信息查询成功,内容为{}", JSON.toJSONString(product));
        return product;
    }
}

  1. 启动工程,等到数据库表创建完毕之后,加入测试数据
INSERT INTO shop_product VALUE(NULL,'小米','1000','5000');
INSERT INTO shop_product VALUE(NULL,'华为','2000','5000');
INSERT INTO shop_product VALUE(NULL,'苹果','3000','5000');
INSERT INTO shop_product VALUE(NULL,'OPPO','4000','5000');

2.5 创建订单微服务

  1. 创建一个名为 shop-order 的模块,并添加springboot依赖
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud-alibaba</artifactId>
        <groupId>com.itsqh</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>shop-order</artifactId>

    <dependencies>
        <!--springboot-web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--shop-common-->
        <dependency>
            <groupId>com.itsqh</groupId>
            <artifactId>shop-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

</project>
  1. 创建工程的主类
/**
 *
 *@description: 订单服务
 *@author: Shiqinghu
 *@time: 2020/12/2 14:33
 */
@SpringBootApplication
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class,args);
    }
}

  1. 创建配置文件application.yml
server:
  port: 8091
spring:
  application:
    name: service-order
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql:///shop?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
    username: root
    password: root
  jpa:
    properties:
      hibernate:
        hbm2ddl:
          auto: update #Springjpa默认创建数据表
        dialect: org.hibernate.dialect.MySQL5InnoDBDialect
  1. 创建OrderDao接口
public interface OrderDao extends JpaRepository<Order,Long> {
}
  1. 创建OrderService接口和实现类
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderDao orderDao;

    @Override
    public void createOrder(Order order) {
        orderDao.save(order);
    }
}

  1. 创建RestTemplate
@SpringBootApplication
public class OrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class,args);
    }

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

  1. 创建Controller

    @RestController
    @Slf4j
    public class OrderController {
        @Autowired
        private RestTemplate restTemplate;
        @Autowired
        private OrderService orderService;
       
        //准备买1件商品
        @GetMapping("/order/prod/{pid}")
        public Order order(@PathVariable("pid") Integer pid) {
            log.info(">>客户下单,这时候要调用商品微服务查询商品信息");
            //通过restTemplate调用商品微服务
            Product product = restTemplate.getForObject("http://localhost:8081/product/" + pid, Product.class);
            log.info(">>商品信息,查询结果:" + JSON.toJSONString(product));
            Order order = new Order();
            order.setUid(1);
            order.setUsername("测试用户");
            order.setPid(product.getPid());
            order.setPname(product.getPname());
            order.setPprice(product.getPprice());
            order.setNumber(1);
            orderService.save(order);
            return order;
        }
    }
    

    读者需要启动以上微服务测试通过,方可继续添加注册Nacos

3 Nacos Discovery–服务治理

3.1 搭建Nacos环境

第1步: 安装nacos

下载地址: https://github.com/alibaba/nacos/releases

下载zip格式的安装包,然后进行解压缩操作

第2步: 启动nacos

#切换目录

cd nacos/bin

#命令启动

startup.cmd -m standalone

第3步: 访问nacos 打开浏览器输入http://localhost:8848/nacos,即可访问服务, 默认密码是nacos/nacos

3.2 将商品微服务注册到nacos

接下来开始修改 shop-product 模块的代码, 将其注册到nacos服务上

  1. 在pom.xml中添加nacos的依赖
<!--nacos客户端-->
<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
</dependency>
  1. 在主类上添加@EnableDiscoveryClient注解
@SpringBootApplication
@EnableDiscoveryClient//开启nacos客户端
public class OrderApplication {
  1. 在application.yml中添加nacos服务的地址
Spring:  
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
  1. 启动服务, 观察nacos的控制面板中是否有注册上来的商品微服务
    在这里插入图片描述

3.3 将订单微服务注册到nacos

同3.2一样操作1、2、3步骤即可,重复步骤此处省略…

修改代码通过Nacos注册中心获取服务端IP地址,核心代码如下

  1. 引入Bean
@Autowired
private DiscoveryClient discoveryClient;
  1. 通过discoveryClient方法,传入参数服务名称获取Nacos服务端的注册表
//从nacos中获取服务地址
List<ServiceInstance> instances = discoveryClient.getInstances("service-product");
ServiceInstance serviceInstance = instances.get(0);
//服务端IP
String host = serviceInstance.getHost();
//服务端端口
int port = serviceInstance.getPort();
3. 修改Rest请求方式
//通过restTemplate调用商品微服务
restTemplate.getForObject("http://" + host + ":" + port + "/product/" + pid,Product.class);
  1. 完整代码
@RestController
@Slf4j
public class OrderController {
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private OrderService orderService;
    @Autowired
    private DiscoveryClient discoveryClient;
    //准备买1件商品
    @GetMapping("/order/prod/{pid}")
    public Order order(@PathVariable("pid") Integer pid) {
        log.info(">>客户下单,这时候要调用商品微服务查询商品信息");
        //从nacos中获取服务地址
        ServiceInstance serviceInstance =
                discoveryClient.getInstances("service-product").get(0);
        String url = serviceInstance.getHost() + ":" + serviceInstance.getPort();
        log.info(">>从nacos中获取到的微服务地址为:" + url);
        //通过restTemplate调用商品微服务
        Product product = restTemplate.getForObject(
                "http://" + url + "/product/" + pid, Product.class);
        
        log.info(">>商品信息,查询结果:" + JSON.toJSONString(product));
        Order order = new Order();
        order.setUid(1);
        order.setUsername("测试用户");
        order.setPid(product.getPid());

        order.setPname(product.getPname());
        order.setPprice(product.getPprice());
        order.setNumber(1);
        orderService.save(order);
        return order;
    }
}

3.4 基于Ribbon实现负载均衡

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

根据负载均衡发生位置的不同,一般分为服务端负载均衡和客户端负载均衡。

在这里插入图片描述
在这里插入图片描述

服务端负载均衡指的是发生在服务提供者一方,比如常见的nginx负载均衡

而客户端负载均衡指的是发生在服务请求的一方,也就是在发送请求之前已经选好了由哪个实例处理请求

Ribbon是Spring Cloud的一个组件, 它可以让我们使用一个注解就能轻松的搞定负载均衡

第1步:在RestTemplate 的生成方法上添加@LoadBalanced注解

@Bean
@LoadBalanced
public RestTemplate restTemplate() {
	return new RestTemplate();
}

第2步:修改服务调用的方法

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

我们可以通过修改配置来调整Ribbon的负载均衡策略,具体代码如下

service-product: # 调用的提供者的名称
  ribbon:
    #RoundRobinRule 轮询(默认)  RandomRule 随机 BestAvailableRule 最小的并发请求
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule

3.5 基于Feign实现服务调用和负载

Feign是Spring Cloud提供的一个声明式的伪Http客户端

它使得调用远程服务就像调用本地服务 一样简单, 只需要创建一个接口并添加一个注解即可。

Nacos很好的兼容了Feign, Feign默认集成了 Ribbon

所以在Nacos下使用Fegin默认就实现了负 载均衡的效果。

  1. 加入Feign依赖
<!--fegin-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  1. 在主类上添加Feign注解
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients//开启Fegin
public class OrderApplication {}
  1. 创建一个service, 并使用Fegin实现微服务调用
@FeignClient("service-product")//声明调用的提供者的name
public interface ProductService {
    //指定调用提供者的哪个方法
    //@FeignClient+@GetMapping 就是一个完整的请求路径 http://serviceproduct/product/{pid}
    @GetMapping(value = "/product/{pid}")
    Product findByPid(@PathVariable("pid") Integer pid);
}
  1. 修改controller代码,并启动验证
@RestController
@Slf4j
public class OrderController {
    @Autowired
    private OrderService orderService;
    @Autowired
    private ProductService productService;
    //准备买1件商品
    @GetMapping("/order/prod/{pid}")
    public Order order(@PathVariable("pid") Integer pid) {
        log.info(">>客户下单,这时候要调用商品微服务查询商品信息");
        //通过fegin调用商品微服务
        Product product = productService.findByPid(pid);
        log.info(">>商品信息,查询结果:" + JSON.toJSONString(product));
        Order order = new Order();
        order.setUid(1);
        order.setUsername("测试用户");
        order.setPid(product.getPid());
        order.setPname(product.getPname());
        order.setPprice(product.getPprice());
        order.setNumber(1);
        orderService.save(order);
        return order;
    }
}

参考资料:

https://www.bilibili.com/video/BV1VJ411X7xX?from=search&seid=1805218605156498019

以上仅为博主学习笔记,仅供参考!如有错误,感谢指出!

获取源码,关注公共号 Java编程与思想,后台回复:nacosym

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值