注意:这里我创建工程和依赖管理的方式和视频有出入,请酌情参考

热部署Devtools

Adding devtools to your project

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-devtools</artifactId>
  4. <scope>runtime</scope>
  5. <optional>true</optional>
  6. </dependency>

Enabling automatic build

image.png

Update the value of

Ctrl+Shift+Alt+/选择Registry…
image.png
compiler.automake.allow.when.app.running -> 自动编译
compile.document.save.trigger.delay -> 自动更新文件;它主要是针对静态文件如JS CSS的更新,将延迟时间减少后,直接按F5刷新页面就能看到效果!
image.png

重启IDEA

项目初始化

生产者与服务站远程调用

生产者

1.创建cloud-provider生产者
目录结构
image.png
pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <groupId>com.example</groupId>
  6. <artifactId>cloud-provider</artifactId>
  7. <version>0.0.1-SNAPSHOT</version>
  8. <name>cloud-provider</name>
  9. <parent>
  10. <groupId>com.example</groupId>
  11. <artifactId>zxsc</artifactId>
  12. <version>0.0.1-SNAPSHOT</version>
  13. </parent>
  14. <dependencies>
  15. <dependency>
  16. <groupId>org.springframework.boot</groupId>
  17. <artifactId>spring-boot-starter-web</artifactId>
  18. </dependency>
  19. <dependency>
  20. <groupId>org.springframework.boot</groupId>
  21. <artifactId>spring-boot-starter-actuator</artifactId>
  22. </dependency>
  23. <dependency>
  24. <groupId>org.mybatis.spring.boot</groupId>
  25. <artifactId>mybatis-spring-boot-starter</artifactId>
  26. </dependency>
  27. <dependency>
  28. <groupId>com.alibaba</groupId>
  29. <artifactId>druid-spring-boot-starter</artifactId>
  30. <version>1.1.10</version>
  31. </dependency>
  32. <dependency>
  33. <groupId>mysql</groupId>
  34. <artifactId>mysql-connector-java</artifactId>
  35. </dependency>
  36. <dependency>
  37. <groupId>org.springframework.boot</groupId>
  38. <artifactId>spring-boot-starter-jdbc</artifactId>
  39. </dependency>
  40. <dependency>
  41. <groupId>org.springframework.boot</groupId>
  42. <artifactId>spring-boot-devtools</artifactId>
  43. <scope>runtime</scope>
  44. <optional>true</optional>
  45. </dependency>
  46. <dependency>
  47. <groupId>org.projectlombok</groupId>
  48. <artifactId>lombok</artifactId>
  49. <optional>true</optional>
  50. </dependency>
  51. <dependency>
  52. <groupId>org.springframework.boot</groupId>
  53. <artifactId>spring-boot-starter-test</artifactId>
  54. <scope>test</scope>
  55. </dependency>
  56. </dependencies>
  57. </project>

2.配置yml

  1. server:
  2. port: 8001
  3. spring:
  4. application:
  5. name: cloud-payment-service
  6. datasource:
  7. type: com.alibaba.druid.pool.DruidDataSource
  8. driver-class-name: com.mysql.jdbc.Driver
  9. url: jdbc:mysql://ip:3306/cloud2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
  10. username: root
  11. password: root
  12. mybatis:
  13. mapperLocations: classpath:/mappers/*.xml
  14. type-aliases-package: com.example.cloudprovider.model

3.写model、mapper、service、serviceimpl

  1. package com.example.cloudprovider.model;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. import java.io.Serializable;
  6. @Data
  7. @AllArgsConstructor
  8. @NoArgsConstructor
  9. public class Payment implements Serializable {
  10. private Long id;
  11. private String serial;
  12. }
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3. <mapper namespace="com.example.cloudprovider.mapper.PaymentMapper">
  4. <insert id="create" useGeneratedKeys="true" keyProperty="id">
  5. insert into payment(serial) values(#{serial});
  6. </insert>
  7. <resultMap id="BaseResultMap" type="com.example.cloudprovider.model.Payment">
  8. <id column="id" property="id" jdbcType="BIGINT"></id>
  9. <result column="serial" property="serial" jdbcType="VARCHAR"></result>
  10. </resultMap>
  11. <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
  12. select * from payment where id=#{id}
  13. </select>
  14. </mapper>
  1. package com.example.cloudprovider.mapper;
  2. import com.example.cloudprovider.model.Payment;
  3. import org.apache.ibatis.annotations.Mapper;
  4. import org.apache.ibatis.annotations.Param;
  5. import org.springframework.stereotype.Component;
  6. /**
  7. * @author liulq
  8. */
  9. //@Component //代替@Repository声明bean
  10. //@Mapper //mybatis提供的,等价:@MapperScan("com.atguigu.springcloud.dao")
  11. //@Repository //spring提供的。在此,只是为了声明bean对象
  12. public interface PaymentMapper {
  13. public int create(Payment payment);
  14. public Payment getPaymentById(@Param("id") Long id);
  15. }

4.写controller

  1. package com.example.cloudprovider.controller;
  2. import com.example.cloudprovider.model.Payment;
  3. import com.example.cloudprovider.service.PaymentService;
  4. import com.example.cloudprovider.util.CommonResult;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.springframework.web.bind.annotation.GetMapping;
  7. import org.springframework.web.bind.annotation.PathVariable;
  8. import org.springframework.web.bind.annotation.PostMapping;
  9. import org.springframework.web.bind.annotation.RestController;
  10. import javax.annotation.Resource;
  11. /**
  12. * @author liulq
  13. */
  14. @RestController
  15. @Slf4j
  16. public class PaymentController {
  17. @Resource
  18. private PaymentService paymentService;
  19. @PostMapping(value = "/payment/create")
  20. public CommonResult<Payment> create(Payment payment){ //埋雷
  21. int result = paymentService.create(payment);
  22. log.info("*****插入结果:"+result);
  23. if (result>0){ //成功
  24. return new CommonResult(200,"插入数据库成功",result);
  25. }else {
  26. return new CommonResult(444,"插入数据库失败",null);
  27. }
  28. }
  29. @GetMapping(value = "/payment/get/{id}")
  30. public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id){
  31. Payment payment = paymentService.getPaymentById(id);
  32. log.info("*****查询结果:"+payment);
  33. if (payment!=null){ //说明有数据,能查询成功
  34. return new CommonResult(200,"查询成功",payment);
  35. }else {
  36. return new CommonResult(444,"没有对应记录,查询ID:"+id,null);
  37. }
  38. }
  39. }

5.写启动类
image.png

调用者

1.创建项目cloud-consumer 调用者
2.写yml

  1. server:
  2. port: 8002
  3. spring:
  4. application:
  5. name: cloud-consumer-order80

3.导入依赖

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <groupId>com.example</groupId>
  6. <artifactId>cloud-consumer</artifactId>
  7. <version>0.0.1-SNAPSHOT</version>
  8. <name>cloud-consumer</name>
  9. <description>cloud-consumer</description>
  10. <parent>
  11. <groupId>com.example</groupId>
  12. <artifactId>zxsc</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. </parent>
  15. <dependencies>
  16. <dependency>
  17. <groupId>org.springframework.boot</groupId>
  18. <artifactId>spring-boot-starter-web</artifactId>
  19. </dependency>
  20. <dependency>
  21. <groupId>org.springframework.boot</groupId>
  22. <artifactId>spring-boot-starter-actuator</artifactId>
  23. </dependency>
  24. <dependency>
  25. <groupId>org.springframework.boot</groupId>
  26. <artifactId>spring-boot-devtools</artifactId>
  27. <scope>runtime</scope>
  28. <optional>true</optional>
  29. </dependency>
  30. <dependency>
  31. <groupId>org.projectlombok</groupId>
  32. <artifactId>lombok</artifactId>
  33. <optional>true</optional>
  34. </dependency>
  35. <dependency>
  36. <groupId>org.springframework.boot</groupId>
  37. <artifactId>spring-boot-starter-test</artifactId>
  38. <scope>test</scope>
  39. </dependency>
  40. </dependencies>
  41. </project>

4.编写RestTemplate 来远程调用
RestTemplate提供了多种便捷访问远程Http服务的方法,是一种简单便捷的访问Restful服务模板类,是Spring 提供的用于访问Rest服务的客户端模板工具集
使用RestTemplate访问Restful接口非常的简单粗暴无脑。(url,requestMap,ResponseBean.class)这三个参数分别代表REST请求地址、请求参数、Http响应转换被转换成的对象类型。

  1. package com.example.cloudconsumer.config;
  2. import org.springframework.boot.SpringBootConfiguration;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.web.client.RestTemplate;
  5. //@Configuration
  6. @SpringBootConfiguration
  7. public class ApplicationContextConfig {
  8. @Bean
  9. //@LoadBalanced
  10. public RestTemplate getRestTemplate(){
  11. return new RestTemplate();
  12. }
  13. }

5.写controller

  1. package com.example.cloudconsumer.controller;
  2. import com.example.cloudconsumer.model.Payment;
  3. import com.example.cloudconsumer.util.CommonResult;
  4. import lombok.extern.slf4j.Slf4j;
  5. import org.springframework.web.bind.annotation.GetMapping;
  6. import org.springframework.web.bind.annotation.PathVariable;
  7. import org.springframework.web.bind.annotation.PostMapping;
  8. import org.springframework.web.bind.annotation.RestController;
  9. import org.springframework.web.client.RestTemplate;
  10. import javax.annotation.Resource;
  11. /**
  12. * @author liulq
  13. */
  14. @RestController
  15. @Slf4j
  16. public class PaymentController {
  17. public static final String PAYMENT_URL = "http://localhost:8001";
  18. @Resource
  19. private RestTemplate restTemplate;
  20. @PostMapping("/consumer/payment/create")
  21. public CommonResult<Payment> create(Payment payment){
  22. return restTemplate.postForObject(PAYMENT_URL+"/payment/create",payment, CommonResult.class); //写操作
  23. }
  24. @GetMapping("/consumer/payment/get/{id}")
  25. public CommonResult<Payment> getPayment(@PathVariable("id") Long id){
  26. return restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);
  27. }
  28. }

测试

生产者 —-》调用调用者
image.png

调用者日志
image.png

项目重构

  • 把公共的类抽取出来

1.创建公共的项目cloud-api-commons
2.导入依赖

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <groupId>com.example</groupId>
  6. <artifactId>cloud-api-commons</artifactId>
  7. <version>0.0.1-SNAPSHOT</version>
  8. <parent>
  9. <groupId>com.example</groupId>
  10. <artifactId>zxsc</artifactId>
  11. <version>0.0.1-SNAPSHOT</version>
  12. </parent>
  13. <dependencies>
  14. <dependency>
  15. <groupId>org.springframework.boot</groupId>
  16. <artifactId>spring-boot-devtools</artifactId>
  17. <scope>runtime</scope>
  18. <optional>true</optional>
  19. </dependency>
  20. <dependency>
  21. <groupId>org.projectlombok</groupId>
  22. <artifactId>lombok</artifactId>
  23. <optional>true</optional>
  24. </dependency>
  25. <dependency>
  26. <groupId>cn.hutool</groupId>
  27. <artifactId>hutool-all</artifactId>
  28. <version>5.1.0</version>
  29. </dependency>
  30. </dependencies>
  31. </project>

3.抽取公共的类
image.png

eurekaServer 端服务注册中心

1.创建项目eurekaServer 注册端
2.写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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>cloud-eureka-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>cloud-eureka-server</name>
    <description>cloud-eureka-server</description>


    <parent>
        <groupId>com.example</groupId>
        <artifactId>zxsc</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <dependencies>
<!--        eureka-server的注册-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</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>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
    </dependencies>


</project>

3.在启动类加上注解:@EnableEurekaServer
image.png

服务注册到eurekaServer

1.添加依赖:

    <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

2.写pom.xml

#    服务发现
eureka:
  client:
    register-with-eureka: true
    fetchRegistry: true
    service-url:
      defaultZone: http://localhost:7001/eureka

3.启动类加注解: @EnableDiscoveryClient
image.png

测试:

image.png

Ribbon负载均衡服务调用

Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。
简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用。
Ribbon客户端组件提供一系列完善的配置项,如:连接超时,重试等。
简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。

1. LB(负载均衡)

1) 简单的说就是将用户的请求平均分配到多个服务器上,从而达到系统的HA(高可用)。
2) 常见的负载均衡有软件Nginx,LVS,硬件F5等。
3) Ribbon的本地负载均衡客户端 VS Nginx服务端负载均衡区别
· Nginx是服务器负载均衡,客户端所有请求都会交给Nginx,然后,由nginx实现转发请求。即负载均衡是由服务器端完成的。
· Ribbon本地负载均衡,在调用微服务接口时候,会在注册中心上获取注册信息服务列表之后缓存到JVM本地,从而在本地实现RPC远程服务调用。
4) 集中式LB
· 即在服务的消费方和提供方之间使用独立的LB设施(可以是硬件,如F5,也可以是软件,如Nginx),由该设施负责把访问请求通过某种策略转发至服务的提供方;
5) 进程内LB
· 将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器。
· Ribbon就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址。

架构

image.png

Ribbon在工作时分成两步:
第一步,先选择EurekaServer,它优先选择在同一个区域内负载较少的server。
第二步,再根据用户指定的策略,在从server取到的服务注册列表中选择一个地址。其中Ribbon提供了多种策略。比如:轮询、随机和根据响应时间加权。
总结:Ribbon其实就是一个软负载均衡的客户端组件,他可以和其他所需请求的客户端结合使用,和eureka结合只是其中的一个实例。

步骤:

1.创建相同的项目 生产者
image.png
2.修改端口,服务名不变
image.png

3.配置负载均衡
image.png

4.通过服务名去负载均衡访问
image.png

测试

1.发请求8002
image.png
2.发请求8002
image.png
3.Ribbon默认轮询去查询(一边一个调用)

OpenFeign服务接口调用

l Feign是一个声明式的web服务客户端,让编写web服务客户端变得非常容易,只需创建一个接口并在接口上添加注解即可
l SpringCloud对Feign进行了封装,使其支持了SpringMVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。
1.写接口

package com.example.cloudconsumerfeignorder80.service;

import com.example.model.Payment;
import com.example.util.CommonResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

/**
 * @program: zxsc
 * @description:
 * @author: liulq
 * @create: 2022-06-02 09:57
 */
@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService {
    @GetMapping(value = "/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);
}

2.写实现

package com.example.cloudconsumerfeignorder80.controller;

import com.example.cloudconsumerfeignorder80.service.PaymentFeignService;
import com.example.model.Payment;
import com.example.util.CommonResult;
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;

/**
 * @program: zxsc
 * @description:
 * @author: liulq
 * @create: 2022-06-02 10:01
 */
@RestController
public class OrderFeignContoller {

    @Autowired
    private PaymentFeignService paymentFeignService;


    @GetMapping(value = "/consumer/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id){
        return paymentFeignService.getPaymentById(id);
    }
}

3.启动类加注解:@EnableFeignClient

getway网关

  • 三大核心:

Route(路由)
Predicate(断言)
Filter(过滤)
在yml配置:

server:
  port: 9527

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      routes:
        - id: payment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8001   #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/**   #断言,路径相匹配的进行路由

        - id: payment_routh2
          uri: http://localhost:8001
          predicates:
            - Path=/payment/lb/**   #断言,路径相匹配的进行路由
eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://localhost:7001/eureka