SpringCloudAlibaba看的某马视频笔记

本文详述了SpringCloudAlibaba组件的使用,包括服务注册与发现、服务限流降级、分布式配置管理、消息驱动、分布式事务等。重点介绍了Nacos作为服务注册中心和配置中心的配置与应用,以及Sentinel实现服务容错。同时,通过实例展示了微服务间的调用和集成Seata进行分布式事务处理。
摘要由CSDN通过智能技术生成

----------------------------SpringCloudAlibaba----------------------------
SpringCloudAlibaba组件说明:
·服务注册与发现:
适配SpringCloud服务注册与发现标准,默认集成了Ribbon的支持
·服务限流降级:
默认支持Servlet、Feign、RestTemplate、Dubbon、和RocketMQ限流降级功能的接入,可以在运行
时通过控制台实时修改限流降级规则,还支持查看限流降级Metrics监控。
·分布式配置管理:
支持分布式系统中的外部化配置,配置更改时自动刷新。
·消息驱动能力:
基于SpringCloudStream为微服务应用构建消息驱动能力。
·分布式事务:
使用@GlobalTransactional注解,高效并且对业务零侵入地解决分布式事务问题。。
·阿里云对象存储:
阿里云提供的海量、安全、低成本、高可靠的云存储服务。支持在任何应用、任何时间、
任何地点存储和任意类型的数据。
·分布式任务调度:
提供秒级、精准、高可靠、高可用的定时(基于Cron表达式)任务调度服务。同时提供分布式
的任务执行模板,如网格任务。网格任务支持海量子任务均匀分配给所有Worker(schedulerx-client)上执行。
·阿里云短信服务:
覆盖全球的短信服务,友好,高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。
----------------------------Nacos(赖抠死)服务注册与发现----------------------------
一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
官方文档:https://nacos.io/zh-cn/
1.从github上下源码包
2.启动服务

Linux/Unix/Mac
启动命令(standalone代表着单机模式运行,非集群模式):

sh startup.sh -m standalone

如果您使用的是ubuntu系统,或者运行脚本报错提示[[符号找不到,可尝试如下运行:

bash startup.sh -m standalone
Windows
启动命令:

cmd startup.cmd

或者双击startup.cmd运行文件。
端口配置是server.port=8848

---------------------------nacos概述--------------------------
微服务架构中问题:
1.这么多服务,客户端如何访问?
2.这么多服务,服务之间如何通信?
3.这么多服务,如何治理?
4.服务挂了,怎么办?

SpringCloud是一套生态,为了解决微服务架构遇到的问题

SpringCloudNetflix
RestTemplate 远程调用
Eureka高可用组件:注册中心,发现服务
Ribbon+Eureka实现 服务调用 负载均衡
Feign实现服务调用
Hystrix 解决服务熔断、服务降级
Zuul网关、进入统一端口调用
Config配置中心
SpringCloudBus 消息总线
SpringCloudSleuth 链路追踪

ApacheDubbonZookeeper
Dubbon高性能、轻量级的开源Java RPC框架
服务注册注册与发现:Zookeeper
API网关,没有。使用第三方或自己实现
熔断机制没有,使用第三方Hystrix

SpringCloudAlibaba
Sentinel代替了SpiringCloud的Netflix的Hystrix
Ribbon+Nacos实现服务调用与负载均衡
Nacos代替了SpringCloudNetflix的Config配置中心以及Eureka注册和发现
Gateway代替了SpringCloudNetflix的Zuul网关
OpenFeign代替了Feign服务调用
SkyWalking代替了Sleuth链路追踪

-------------------环境搭建----------------------
1、创建一个poject,作为父工程
groupId:con.can.alibaba
artifactId:springcloud-alibaba

1.2、POM添加版本依赖锁定

<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>con.can.alibaba</groupId>
    <artifactId>springcloud-alibaba</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>shop-common</module>
        <module>show-user</module>
    </modules>

    <!-- 父工程 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
    </parent>
    <!-- 依赖版本的锁定 -->
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
        <spring-alibaba.version>2.1.0.RELEASE</spring-alibaba.version>
    </properties>

    <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>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

版本对应
---------------Spring Cloud Version---------------

  1. Spring Cloud Greenwich
  2. Spring Cloud Finchley
  3. Spring Cloud Edgware
    ---------------Spring Cloud Alibaba Version---------------
  4. 2.1.0.RELEASE
  5. 2.0.0.RELEASE
  6. 1.5.0.RELEASE
    ---------------Spring Boot Version---------------
  7. 2.1.X.RELEASE
  8. 2.0.X.RELEASE
  9. 1.5.X.RELEASE

2、创建基础模块
2.1、创建Module
groupId:con.can.alibaba
artifactId:shop-common
2.2、POM引入依赖

<!-- 依赖 -->
    <dependencies>
        <!-- jpa -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!-- JSON序列化 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.62</version>
        </dependency>
        <!-- mysql驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <!-- mybatisPlus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.1</version>
        </dependency>
    </dependencies>

2.3、shop-common模块下创建三个实体类
包名:com.can.pojo
2.4、第一个实体类 User.java

package com.can.pojo;

import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

/**
 * 用户
 */
@Entity(name="shop_user") //是实体类跟数据库表名的对应
@Data
public class User {

    @Id//表示是主键
    //TABLE:使用一个特定的数据库表格来保存主键。
    //SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列。
    //IDENTITY:主键由数据库自动生成(主要是自动增长型)
    //AUTO:主键由程序控制。
    @GeneratedValue(strategy = GenerationType.IDENTITY)//主键生成策略(GenerationType.IDENTITY表示此主键是数据库自增)
    private Integer uid;    //主键
    private String username; //用户名
    private String password; //密码
    private String telephone; //手机号
}

2.5、第二个实体类 Product.java

package com.can.pojo;

import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

/**
 * 商品
 */
@Entity(name = "shop_product")
@Data
public class Product {

    @Id
    //TABLE:使用一个特定的数据库表格来保存主键。
    //SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列。
    //IDENTITY:主键由数据库自动生成(主要是自动增长型)
    //AUTO:主键由程序控制。
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer pid; //主键
    private String pname; //商品名称
    private Double pprice; //商品价格
    private Integer stock; //库存
}

2.6、第三个实体类 Order.java

package com.can.pojo;

import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

/**
 * 订单
 */
@Entity(name = "shop_order")
@Data
public class Order {

    @Id
    //TABLE:使用一个特定的数据库表格来保存主键。
    //SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列。
    //IDENTITY:主键由数据库自动生成(主要是自动增长型)
    //AUTO:主键由程序控制。
    @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; //购买数量
}

3、创建微服务
步骤:
1.创建模块,导入依赖
2.创建SpringBoot主类
3.加入配置类
4.创建必要的接口和实现类(controller service dao)

3.1、创建用户微服务
1.新建一个Moudel
2.artifactId:shop-user
3.java下创建包:com.can
4.新建启动类:UserApplication

package com.can;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class UserApplication {

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

5.resources编写配置文件application.yml

server:
  port: 8071
spring:
  application:
    name: server-user

  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/shop?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    username: root
    password: root

  jpa:
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
    hibernate:
      ddl-auto: update
    show-sql: true

数据库得先创建好

然后编写dao,service,controller
controller:

package com.can.controller;

import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {
}

DAO:

package com.can.dao;

import com.can.pojo.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserDao extends JpaRepository<User,Integer> {
}

service:

package com.can.service;

public interface UserService {
}

serviceImpl:

package com.can.service.imp;

import com.can.service.UserService;

public class UserServiceImpl implements UserService {
}

3.2、创建商品微服务shop-product和订单微服务shop-order
跟用户微服务步骤一样,直接复制粘贴
用户微服务微服务shop-user端口号:8071
商品微服务shop-product端口号:8081
订单微服务shop-order端口号:8091

3.3、商品微服务调用方法测试
1.在controller添加查询商品信息方法

package com.can.controller;

import com.alibaba.fastjson.JSON;
import com.can.pojo.Product;
import com.can.service.ProductService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Slf4j
public class ProductController {

    @Autowired
    private ProductService productService;

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

Service接口添加方法

package com.can.service;

import com.can.pojo.Product;



public interface ProductService {
    //根据Pid查询商品信息
    Product findByPid(Integer pid);
}

ProductService实现类

package com.can.service.imp;

import com.can.dao.ProductDao;
import com.can.pojo.Product;
import com.can.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class ProductServiceImpl implements ProductService {

    @Autowired
    private ProductDao productDao;

    @Override
    public Product findByPid(Integer pid) {
        return productDao.findById(pid).get();
    }
}

然后启动商品微服务
执行url http://localhost:8081/product/1
调用成功即可

4、编写Order微服务
1.Controller添加下单方法

package com.can.controller;

import com.alibaba.fastjson.JSON;
import com.can.pojo.Order;
import com.can.pojo.Product;
import com.can.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@Slf4j
public class OrderController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private OrderService orderService;

    @RequestMapping("/order/prod/{pid}")
    public Order queryOrder(@PathVariable("pid") Integer pid){
        log.info("{}号商品的下单请求,并调用商品微服务查询商品信息",pid);
        //调用商品微服务,查询商品信息
        Product product = restTemplate.getForObject("http://localhost:8081/product/"+pid,Product.class);
        log.info("查询到{}号商品信息,内容是{}",pid, JSON.toJSONString(product));

        //下单(创建订单)
        Order order = new Order();
        order.setUid(1);
        order.setUsername("测试用户1");
        order.setPid(product.getPid());
        order.setPname(product.getPname());
        order.setPprice(product.getPprice());
        order.setNumber(1);

        orderService.createOrder(order);
        log.info("创建订单成功,订单信息为{}",JSON.toJSONString(order));
        return order;
    }
}

Service:

package com.can.service;

import com.can.pojo.Order;

public interface OrderService {
    void createOrder(Order order);
}

Service实现类:

package com.can.service.imp;

import com.can.dao.OrderDao;
import com.can.pojo.Order;
import com.can.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderDao orderDao;

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

dao:

package com.can.dao;

import com.can.pojo.Order;
import com.can.pojo.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface OrderDao extends JpaRepository<Order,Integer> {
}

5、但是这种方式调用服务者会有很大的问题
问题:
//1.一旦服务提供者的地址信息变化了,我们就不得不去修改服务调用者的java代码
//2.提供者做了集群,服务调用者一方无法实现负载均衡去调用
//3.一旦微服务变得越来越多,如何来管理这个服务清单就成了问题

这时候就需要一个服务治理者,服务提供者向服务治理者进行一个注册,然后服务消费者也去服务治理者获取服务信息
通过注册中心动态实现服务治理。

6、Nacos是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。它是SpringCloudAlibaba
组件之一、负责服务注册发现和服务配置,可以这样认为nacos=eureka+config。
6.1、Nacos简介
Nacos致力于帮助n您发现、配置和管理微服务。Nacos提供了一组简单易用的特性集,帮助n您快速实现动态
服务发现、服务配置、服务元数据及流量管理。
nacos的作用就是一个注册中心,用来管理注册上来的各个微服务。

6.2、向服务注册到注册中心nacos中
1.打开之前下载的nacos,默认端口是8848
2.浏览器请求 http://192.168.137.1:8848/nacos/index.html查看是否启动成功
3.在商品product微服务POM中添加nacos客户端相关依赖

<!-- Nacos客户端-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

4.在启动类添加注解@EnableDiscoveryClient //开启用于被注册中心发现
@EnableEurekaClient是只针对于eureka注册中心使用,如果是其他注册中心则使用@EnableDiscoveryClient
在高版本中不加这两个注解也可以被注册到注册中心中了
如果不向被注册中心注册到服务列表中可以通过两种方式
1.application配置文件中添加

spring:
  cloud:
    service-registry:
      auto-registration:
        enabled: false

2.在启动类@EnableDiscoveryClient(autoRegister = false)添加autoRegister = false即可

5.application.yml中添加nacaos配置

cloud: #nacos注册中心ip
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

6.然后启动Product微服务
7.在http://192.168.137.1:8848/nacos/index.html的Nacos的Ui界面的服务管理-服务列表中查询就可以看见商品微服务注册到服务端了
8.将订单微服务也注册到nacaos注册中心,跟商品微服务是同样的步骤1.依赖2.启动类注解3.application.yml配置文件添加nacos配置

7、通过DiscoveryClient动态实现服务调用者调用提供者
1.打开Order订单微服务controller

package com.can.controller;

import com.alibaba.fastjson.JSON;
import com.can.pojo.Order;
import com.can.pojo.Product;
import com.can.service.OrderService;
import lombok.extern.slf4j.Slf4j;
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.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController
@Slf4j
public class OrderController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private OrderService orderService;

    //获取一些配置的信息,得到具体的微服务!
    @Autowired
    private DiscoveryClient discoveryClient;

    @RequestMapping("/order/prod/{pid}")
    public Order queryOrder(@PathVariable("pid") Integer pid){
        log.info("{}号商品的下单请求,并调用商品微服务查询商品信息",pid);

//        Product product = restTemplate.getForObject("http://localhost:8081/product/"+pid,Product.class);

        List<ServiceInstance> instances = discoveryClient.getInstances("server-product-8081");
        ServiceInstance service;
        Product product = null;
        if (instances!=null){
            service = instances.get(0);
             product =
                    restTemplate.getForObject(
                            "http://"+service.getHost()+":"+service.getPort()+"/product/"+pid,Product.class);
        }

        log.info("查询到{}号商品信息,内容是{}",pid, JSON.toJSONString(product));

        //下单(创建订单)
        Order order = new Order();
        order.setUid(1);
        order.setUsername("测试用户1");
        order.setPid(product.getPid());
        order.setPname(product.getPname());
        order.setPprice(product.getPprice());
        order.setNumber(1);

        orderService.createOrder(order);
        log.info("创建订单成功,订单信息为{}",JSON.toJSONString(order));
        return order;
    }

    //解决问题前的实现方法
//    public Order queryOrder(@PathVariable("pid") Integer pid){
//        log.info("{}号商品的下单请求,并调用商品微服务查询商品信息",pid);
//        //调用商品微服务,查询商品信息
//        //问题:
//        //1.一旦服务提供者的地址信息变化了,我们就不得不去修改服务调用者的java代码
//        //2.提供者做了集群,服务调用者一方无法实现负载均衡去调用
//        //3.一旦微服务变得越来越多,如何来管理这个服务清单就成了问题
//        Product product = restTemplate.getForObject("http://localhost:8081/product/"+pid,Product.class);
//        log.info("查询到{}号商品信息,内容是{}",pid, JSON.toJSONString(product));
//
//        //下单(创建订单)
//        Order order = new Order();
//        order.setUid(1);
//        order.setUsername("测试用户1");
//        order.setPid(product.getPid());
//        order.setPname(product.getPname());
//        order.setPprice(product.getPprice());
//        order.setNumber(1);
//
//        orderService.createOrder(order);
//        log.info("创建订单成功,订单信息为{}",JSON.toJSONString(order));
//        return order;
//    }
}

8、上面问题解决了但是又有了新的问题,上面通过DiscoveryClient服务名获取到服务信息,但是获取的服务可能是多个集群的情况
这时候就要考虑到负载均衡了
1.所以我们要添加一个SpringBoot
2.通过idea打开Edit Configurations
3.复制一份ProductApplication
4.VM options修改为-Dserver.port=8082
5.保存,启动,nacosUi界面查看服务是否被注册

8.1、接下来就可以实现负载均衡,解决使用哪个服务
8.2、自定义负载均衡

package com.can.controller;

import com.alibaba.fastjson.JSON;
import com.can.pojo.Order;
import com.can.pojo.Product;
import com.can.service.OrderService;
import lombok.extern.slf4j.Slf4j;
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.PathVariable;
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;

@RestController
@Slf4j
public class OrderController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private OrderService orderService;

    //获取一些配置的信息,得到具体的微服务!
    @Autowired
    private DiscoveryClient discoveryClient;

    //下单--自定义负载均衡
    @RequestMapping("/order/prod/{pid}")
    public Order queryOrder(@PathVariable("pid") Integer pid){
        log.info("{}号商品的下单请求,并调用商品微服务查询商品信息",pid);

//        Product product = restTemplate.getForObject("http://localhost:8081/product/"+pid,Product.class);

        //通过访问名 获取到服务信息
        List<ServiceInstance> instances = discoveryClient.getInstances("server-product-8081");
        //随机选择

        ServiceInstance service;
        Product product = null;
        if (instances!=null){
            int index = new Random().nextInt(instances.size());
            service = instances.get(index);
            product =
                    restTemplate.getForObject(
                            "http://"+service.getHost()+":"+service.getPort()+"/product/"+pid,Product.class);
        }

        log.info("查询到{}号商品信息,内容是{}",pid, JSON.toJSONString(product));

        //下单(创建订单)
        Order order = new Order();
        order.setUid(1);
        order.setUsername("测试用户1");
        order.setPid(product.getPid());
        order.setPname(product.getPname());
        order.setPprice(product.getPprice());
        order.setNumber(1);

        orderService.createOrder(order);
        log.info("创建订单成功,订单信息为{}",JSON.toJSONString(order));
        return order;
    }

    //通过DiscoveryClient获取服务信息,解决动态调用服务的问题
//    @RequestMapping("/order/prod/{pid}")
//    public Order queryOrder(@PathVariable("pid") Integer pid){
//        log.info("{}号商品的下单请求,并调用商品微服务查询商品信息",pid);
//
        Product product = restTemplate.getForObject("http://localhost:8081/product/"+pid,Product.class);
//
//        //通过访问名 获取到服务信息
//        List<ServiceInstance> instances = discoveryClient.getInstances("server-product-8081");
//        ServiceInstance service;
//        Product product = null;
//        if (instances!=null){
//            service = instances.get(0);
//             product =
//                    restTemplate.getForObject(
//                            "http://"+service.getHost()+":"+service.getPort()+"/product/"+pid,Product.class);
//        }
//
//        log.info("查询到{}号商品信息,内容是{}",pid, JSON.toJSONString(product));
//
//        //下单(创建订单)
//        Order order = new Order();
//        order.setUid(1);
//        order.setUsername("测试用户1");
//        order.setPid(product.getPid());
//        order.setPname(product.getPname());
//        order.setPprice(product.getPprice());
//        order.setNumber(1);
//
//        orderService.createOrder(order);
//        log.info("创建订单成功,订单信息为{}",JSON.toJSONString(order));
//        return order;
//    }

    //解决问题前的实现方法
//    public Order queryOrder(@PathVariable("pid") Integer pid){
//        log.info("{}号商品的下单请求,并调用商品微服务查询商品信息",pid);
//        //调用商品微服务,查询商品信息
//        //问题:
//        //1.一旦服务提供者的地址信息变化了,我们就不得不去修改服务调用者的java代码
//        //2.提供者做了集群,服务调用者一方无法实现负载均衡去调用
//        //3.一旦微服务变得越来越多,如何来管理这个服务清单就成了问题
//        Product product = restTemplate.getForObject("http://localhost:8081/product/"+pid,Product.class);
//        log.info("查询到{}号商品信息,内容是{}",pid, JSON.toJSONString(product));
//
//        //下单(创建订单)
//        Order order = new Order();
//        order.setUid(1);
//        order.setUsername("测试用户1");
//        order.setPid(product.getPid());
//        order.setPname(product.getPname());
//        order.setPprice(product.getPprice());
//        order.setNumber(1);
//
//        orderService.createOrder(order);
//        log.info("创建订单成功,订单信息为{}",JSON.toJSONString(order));
//        return order;
//    }
}

8.3、基于Ribbon实现负载均衡
Ribbon是SpringCloud的一个组件,它可以使用一个注解就能轻松的搞定负载均衡
1.第一步在RestTemplate的生成方法上添加LoadBalanced注解

package com.can;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
//autoRegister = false代表不被注册中心注册到服务列表
//@EnableDiscoveryClient(autoRegister = false)
@EnableDiscoveryClient
public class OrderApplication {

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

    @Bean
    @LoadBalanced //基于Ribbon负载均衡的注解
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

2.修改调用方式,有了Ribbon可以直接使用服务名(spring.application.name)来调用方法了
Ribbon负载均衡,默认策略是 轮询

package com.can.controller;

import com.alibaba.fastjson.JSON;
import com.can.pojo.Order;
import com.can.pojo.Product;
import com.can.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;


@RestController
@Slf4j
public class OrderController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private OrderService orderService;

    //获取一些配置的信息,得到具体的微服务!
    @Autowired
    private DiscoveryClient discoveryClient;

    //下单--Ribbon负载均衡(默认是轮询)
    @RequestMapping("/order/prod/{pid}")
    public Order queryOrder(@PathVariable("pid") Integer pid){
        log.info("{}号商品的下单请求,并调用商品微服务查询商品信息",pid);

        String url = "http://server-product-8081";
        Product product =
                    restTemplate.getForObject(
                            url+"/product/"+pid,Product.class);

        log.info("查询到{}号商品信息,内容是{}",pid, JSON.toJSONString(product));

        //下单(创建订单)
        Order order = new Order();
        order.setUid(1);
        order.setUsername("测试用户1");
        order.setPid(product.getPid());
        order.setPname(product.getPname());
        order.setPprice(product.getPprice());
        order.setNumber(1);

        orderService.createOrder(order);
        log.info("创建订单成功,订单信息为{}",JSON.toJSONString(order));
        return order;
    }

//    //下单--自定义负载均衡
//    @RequestMapping("/order/prod/{pid}")
//    public Order queryOrder(@PathVariable("pid") Integer pid){
//        log.info("{}号商品的下单请求,并调用商品微服务查询商品信息",pid);
//
        Product product = restTemplate.getForObject("http://localhost:8081/product/"+pid,Product.class);
//
//        //通过访问名 获取到服务信息
//        List<ServiceInstance> instances = discoveryClient.getInstances("server-product-8081");
//        //随机选择
//
//        ServiceInstance service;
//        Product product = null;
//        if (instances!=null){
//            int index = new Random().nextInt(instances.size());
//            service = instances.get(index);
//            product =
//                    restTemplate.getForObject(
//                            "http://"+service.getHost()+":"+service.getPort()+"/product/"+pid,Product.class);
//        }
//
//        log.info("查询到{}号商品信息,内容是{}",pid, JSON.toJSONString(product));
//
//        //下单(创建订单)
//        Order order = new Order();
//        order.setUid(1);
//        order.setUsername("测试用户1");
//        order.setPid(product.getPid());
//        order.setPname(product.getPname());
//        order.setPprice(product.getPprice());
//        order.setNumber(1);
//
//        orderService.createOrder(order);
//        log.info("创建订单成功,订单信息为{}",JSON.toJSONString(order));
//        return order;
//    }

    //通过DiscoveryClient获取服务信息,解决动态调用服务的问题
//    @RequestMapping("/order/prod/{pid}")
//    public Order queryOrder(@PathVariable("pid") Integer pid){
//        log.info("{}号商品的下单请求,并调用商品微服务查询商品信息",pid);
//
        Product product = restTemplate.getForObject("http://localhost:8081/product/"+pid,Product.class);
//
//        //通过访问名 获取到服务信息
//        List<ServiceInstance> instances = discoveryClient.getInstances("server-product-8081");
//        ServiceInstance service;
//        Product product = null;
//        if (instances!=null){
//            service = instances.get(0);
//             product =
//                    restTemplate.getForObject(
//                            "http://"+service.getHost()+":"+service.getPort()+"/product/"+pid,Product.class);
//        }
//
//        log.info("查询到{}号商品信息,内容是{}",pid, JSON.toJSONString(product));
//
//        //下单(创建订单)
//        Order order = new Order();
//        order.setUid(1);
//        order.setUsername("测试用户1");
//        order.setPid(product.getPid());
//        order.setPname(product.getPname());
//        order.setPprice(product.getPprice());
//        order.setNumber(1);
//
//        orderService.createOrder(order);
//        log.info("创建订单成功,订单信息为{}",JSON.toJSONString(order));
//        return order;
//    }

    //解决问题前的实现方法
//    public Order queryOrder(@PathVariable("pid") Integer pid){
//        log.info("{}号商品的下单请求,并调用商品微服务查询商品信息",pid);
//        //调用商品微服务,查询商品信息
//        //问题:
//        //1.一旦服务提供者的地址信息变化了,我们就不得不去修改服务调用者的java代码
//        //2.提供者做了集群,服务调用者一方无法实现负载均衡去调用
//        //3.一旦微服务变得越来越多,如何来管理这个服务清单就成了问题
//        Product product = restTemplate.getForObject("http://localhost:8081/product/"+pid,Product.class);
//        log.info("查询到{}号商品信息,内容是{}",pid, JSON.toJSONString(product));
//
//        //下单(创建订单)
//        Order order = new Order();
//        order.setUid(1);
//        order.setUsername("测试用户1");
//        order.setPid(product.getPid());
//        order.setPname(product.getPname());
//        order.setPprice(product.getPprice());
//        order.setNumber(1);
//
//        orderService.createOrder(order);
//        log.info("创建订单成功,订单信息为{}",JSON.toJSONString(order));
//        return order;
//    }
}

3.如果需要其他策略就在yml中配置

server-product-8081: #调用的提供者的名称
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule  #负载均衡的规则,表示加权规则,yml配置优先级第一,Java代码第二,默认的最后
    

8.4、基于Feign实现服务调用
1.Feign是SpringCloud提供的一个声明式的伪Http客户端,它使得调用远程服务就像调用本地服务一样简单,
只需要创建一个接口并添加一个注解即可。
2.Nacos很好得兼容了Feign、Feign默认集成了Ribbon,所以在Nacos下使用Feign默认就实现了负载均衡得效果.
3.Feign的使用
3.1.加入Feign的依赖

<!-- Feign依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

3.2.启动上添加注解 @EnableFeignClients//开启feign客户端

package com.can;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
//autoRegister = false代表不被注册中心注册到服务列表
//@EnableDiscoveryClient(autoRegister = false)
@EnableDiscoveryClient
@EnableFeignClients//开启feign客户端
public class OrderApplication {

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

    @Bean
    @LoadBalanced //基于Ribbon负载均衡的注解
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

3.3、新增一个Feign接口ProductService,用于实现Feign服务调用

package com.can.service;

import com.can.pojo.Product;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@FeignClient(value = "server-product-8081")
//@FeignClient:
//value用于指定 Nacos下的哪个微服务
public interface ProductService {

    @RequestMapping("/product/{pid}")   //指定请求的URL
    Product findByPid(@PathVariable("pid") Integer pid);
}

3.3.修改订单微服务的controller调用方法

package com.can.controller;

import com.alibaba.fastjson.JSON;
import com.can.pojo.Order;
import com.can.pojo.Product;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值