父工程构建

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <groupId>org.example</groupId>
  7. <artifactId>springcloudlearn</artifactId>
  8. <packaging>pom</packaging>
  9. <version>1.0-SNAPSHOT</version>
  10. <modules>
  11. <module>payment8001</module>
  12. <module>order80</module>
  13. </modules>
  14. <properties>
  15. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  16. <maven.compiler.source>8</maven.compiler.source>
  17. <maven.compiler.target>8</maven.compiler.target>
  18. <junit.version>4.12</junit.version>
  19. <log4j.version>1.2.17</log4j.version>
  20. <lombok.version>1.16.18</lombok.version>
  21. <mysql.version>5.1.47</mysql.version>
  22. <druid.version>1.1.16</druid.version>
  23. <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
  24. </properties>
  25. <!-- 子模块继承之后,提供作用:
  26. 锁定版本+子modlue不用写groupId和version -->
  27. <dependencyManagement>
  28. <dependencies>
  29. <!--spring boot 2.2.2-->
  30. <dependency>
  31. <groupId>org.springframework.boot</groupId>
  32. <artifactId>spring-boot-dependencies</artifactId>
  33. <version>2.2.2.RELEASE</version>
  34. <type>pom</type>
  35. <scope>import</scope>
  36. </dependency>
  37. <!--spring cloud Hoxton.SR1-->
  38. <dependency>
  39. <groupId>org.springframework.cloud</groupId>
  40. <artifactId>spring-cloud-dependencies</artifactId>
  41. <version>Hoxton.SR1</version>
  42. <type>pom</type>
  43. <scope>import</scope>
  44. </dependency>
  45. <!--spring cloud alibaba 2.1.0.RELEASE-->
  46. <dependency>
  47. <groupId>com.alibaba.cloud</groupId>
  48. <artifactId>spring-cloud-alibaba-dependencies</artifactId>
  49. <version>2.1.0.RELEASE</version>
  50. <type>pom</type>
  51. <scope>import</scope>
  52. </dependency>
  53. <dependency>
  54. <groupId>mysql</groupId>
  55. <artifactId>mysql-connector-java</artifactId>
  56. <version>${mysql.version}</version>
  57. </dependency>
  58. <dependency>
  59. <groupId>com.alibaba</groupId>
  60. <artifactId>druid</artifactId>
  61. <version>${druid.version}</version>
  62. </dependency>
  63. <dependency>
  64. <groupId>org.mybatis.spring.boot</groupId>
  65. <artifactId>mybatis-spring-boot-starter</artifactId>
  66. <version>${mybatis.spring.boot.version}</version>
  67. </dependency>
  68. <dependency>
  69. <groupId>junit</groupId>
  70. <artifactId>junit</artifactId>
  71. <version>${junit.version}</version>
  72. </dependency>
  73. <dependency>
  74. <groupId>log4j</groupId>
  75. <artifactId>log4j</artifactId>
  76. <version>${log4j.version}</version>
  77. </dependency>
  78. <dependency>
  79. <groupId>org.projectlombok</groupId>
  80. <artifactId>lombok</artifactId>
  81. <version>${lombok.version}</version>
  82. <optional>true</optional>
  83. </dependency>
  84. </dependencies>
  85. </dependencyManagement>
  86. <build>
  87. <plugins>
  88. <plugin>
  89. <groupId>org.springframework.boot</groupId>
  90. <artifactId>spring-boot-maven-plugin</artifactId>
  91. <configuration>
  92. <fork>true</fork>
  93. <addResources>true</addResources>
  94. </configuration>
  95. </plugin>
  96. </plugins>
  97. </build>
  98. </project>

dependencyManagement作为版本依赖的工具,使用pom.xml中的dependencyManagement元素能让所有在子项目中引用个依赖而不用显式的列出版本量。

支付模块构建流程

1、POM文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <parent>
  6. <artifactId>springcloudlearn</artifactId>
  7. <groupId>org.example</groupId>
  8. <version>1.0-SNAPSHOT</version>
  9. </parent>
  10. <modelVersion>4.0.0</modelVersion>
  11. <artifactId>payment8001</artifactId>
  12. <properties>
  13. <maven.compiler.source>8</maven.compiler.source>
  14. <maven.compiler.target>8</maven.compiler.target>
  15. </properties>
  16. <dependencies>
  17. <dependency>
  18. <groupId>org.springframework.boot</groupId>
  19. <artifactId>spring-boot-starter-web</artifactId>
  20. </dependency>
  21. <dependency>
  22. <groupId>org.springframework.boot</groupId>
  23. <artifactId>spring-boot-starter-actuator</artifactId>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.mybatis.spring.boot</groupId>
  27. <artifactId>mybatis-spring-boot-starter</artifactId>
  28. </dependency>
  29. <dependency>
  30. <groupId>com.alibaba</groupId>
  31. <artifactId>druid-spring-boot-starter</artifactId>
  32. <version>1.1.10</version>
  33. </dependency>
  34. <!--mysql-connector-java-->
  35. <dependency>
  36. <groupId>mysql</groupId>
  37. <artifactId>mysql-connector-java</artifactId>
  38. </dependency>
  39. <!--jdbc-->
  40. <dependency>
  41. <groupId>org.springframework.boot</groupId>
  42. <artifactId>spring-boot-starter-jdbc</artifactId>
  43. </dependency>
  44. <dependency>
  45. <groupId>org.springframework.boot</groupId>
  46. <artifactId>spring-boot-devtools</artifactId>
  47. <scope>runtime</scope>
  48. <optional>true</optional>
  49. </dependency>
  50. <dependency>
  51. <groupId>org.projectlombok</groupId>
  52. <artifactId>lombok</artifactId>
  53. <optional>true</optional>
  54. </dependency>
  55. <dependency>
  56. <groupId>org.springframework.boot</groupId>
  57. <artifactId>spring-boot-starter-test</artifactId>
  58. <scope>test</scope>
  59. </dependency>
  60. </dependencies>
  61. </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: org.gjt.mm.mysql.Driver # mysql驱动包
  9. url: jdbc:mysql://localhost:3306/springcloud?useUnicode=true&characterEncoding=utf-8&useSSL=false
  10. username: root
  11. password: 123456
  12. mybatis:
  13. type-aliases-package: com.learn.springcloud.entities
  14. mapper-locations: classpath:mapper/*.xml

3、启动类

  1. package com.learn.springcloud;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. @SpringBootApplication
  5. public class Payment8001 {
  6. public static void main(String[] args) {
  7. SpringApplication.run(Payment8001.class,args);
  8. }
  9. }

4、业务类

实体类

  1. package com.learn.springcloud.entities;
  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. package com.learn.springcloud.entities;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. @Data
  6. @AllArgsConstructor
  7. @NoArgsConstructor
  8. public class CommonResult<T> {
  9. private Integer code;
  10. private String message;
  11. private T data;
  12. public CommonResult(Integer code, String message){
  13. this(code,message,null);
  14. }
  15. }

Dao层

  1. package com.learn.springcloud.dao;
  2. import com.learn.springcloud.entities.Payment;
  3. import org.apache.ibatis.annotations.Mapper;
  4. import org.apache.ibatis.annotations.Param;
  5. @Mapper
  6. public interface PaymentDao {
  7. public int create(Payment payment);
  8. public Payment getPaymentById(@Param("id") Long id);
  9. }

Mapper文件

  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.learn.springcloud.dao.PaymentDao">
  4. <insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id">
  5. insert into payment(serial) values(#{serial});
  6. </insert>
  7. <resultMap id="BaseResultMap" type="com.learn.springcloud.entities.Payment">
  8. <id column="id" property="id" jdbcType="BIGINT"/>
  9. <id column="serial" property="serial" jdbcType="VARCHAR"/>
  10. </resultMap>
  11. <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
  12. select * from payment where id=#{id};
  13. </select>
  14. </mapper>

Service层

  1. package com.learn.springcloud.service;
  2. import com.learn.springcloud.entities.Payment;
  3. import org.apache.ibatis.annotations.Param;
  4. public interface PaymentService {
  5. public int create(Payment payment);
  6. public Payment getPaymentById(@Param("id") Long id);
  7. }

impl

  1. package com.learn.springcloud.service.impl;
  2. import com.learn.springcloud.dao.PaymentDao;
  3. import com.learn.springcloud.entities.Payment;
  4. import com.learn.springcloud.service.PaymentService;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.stereotype.Service;
  7. import javax.annotation.Resource;
  8. @Service
  9. public class PaymentServiceImpl implements PaymentService {
  10. @Resource
  11. private PaymentDao paymentDao;
  12. @Override
  13. public int create(Payment payment) {
  14. return paymentDao.create(payment);
  15. }
  16. @Override
  17. public Payment getPaymentById(Long id) {
  18. return paymentDao.getPaymentById(id);
  19. }
  20. }

Controller层

  1. package com.learn.springcloud.controller;
  2. import com.learn.springcloud.entities.CommonResult;
  3. import com.learn.springcloud.entities.Payment;
  4. import com.learn.springcloud.service.PaymentService;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.springframework.web.bind.annotation.*;
  7. import javax.annotation.Resource;
  8. @RestController
  9. @Slf4j
  10. public class PaymentController {
  11. @Resource
  12. private PaymentService paymentService;
  13. @PostMapping(value = "/payment/create")
  14. public CommonResult create(@RequestBody Payment payment){
  15. int result = paymentService.create(payment);
  16. log.info("插入结果"+result);
  17. if(result > 0) {
  18. return new CommonResult(200, "创建成功", result);
  19. }else{
  20. return new CommonResult(404,"创建失败",null);
  21. }
  22. }
  23. @GetMapping(value ="/payment/get/{id}")
  24. public CommonResult getPaymentById(@PathVariable("id") Long id){
  25. Payment result = paymentService.getPaymentById(id);
  26. log.info("插入结果"+result);
  27. if(result != null) {
  28. return new CommonResult(200, "查询成功", result);
  29. }else{
  30. return new CommonResult(404,"查询 失败",null);
  31. }
  32. }
  33. }

查询结果
image.png

消费者订单构建模块

image.png
也是如此,但是为了使得消费者能够访问到支付模块中的数据,就需要使用resttemplate来远程访问http中的数据。
RestTemplate配置类

  1. package com.learn.springcloud.config;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.web.client.RestTemplate;
  5. @Configuration
  6. public class ApplicationContextConfig {
  7. @Bean
  8. public RestTemplate getRestTemplate(){
  9. return new RestTemplate();
  10. }
  11. }

Controller层

  1. package com.learn.springcloud.controller;
  2. import com.learn.springcloud.entities.CommonResult;
  3. import com.learn.springcloud.entities.Payment;
  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. @RestController
  12. @Slf4j
  13. public class OrderController {
  14. public static final String PAYMENT_URL="http://localhost:8001";
  15. @Resource
  16. private RestTemplate restTemplate;
  17. @PostMapping("/consumer/payment/create")
  18. public CommonResult create(Payment payment){
  19. return restTemplate.postForObject(PAYMENT_URL+"/payment/create",payment,CommonResult.class);
  20. }
  21. @GetMapping("consumer/payment/get/{id}")
  22. public CommonResult getPaymentById(@PathVariable("id") Long id){
  23. return restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);
  24. }
  25. }

查询结果
image.png
可以看到,通过consumer途径访问到了支付模块中的数据。

公共模块的重建

image.png
可以看到支付模块和消费者模块都存在公共的部分,因此我们需要将公共的模块抽取处理。

POM

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

公共类的抽取
image.png
注:然后对该模块进行maven clear install之前,必须对父工程先进行clear install,保证项目的正常运行
依赖导入

  1. <dependency>
  2. <groupId>org.example</groupId>
  3. <artifactId>springcloud-api-common</artifactId>
  4. <version>${project.version}</version>
  5. </dependency>

Eureka

在传统的RPC远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂,所以需要使用服务治理,管理服务于服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。

Eureka组件

Eureka Server提供服务注册服务
各个微服务节点通过配置启动后,会在EurekaServer中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到。

EurekaClient通过注册中心进行访问
它是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除(默认90秒)

项目构建

1、POM

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <parent>
  6. <artifactId>springcloudlearn</artifactId>
  7. <groupId>org.example</groupId>
  8. <version>1.0-SNAPSHOT</version>
  9. </parent>
  10. <modelVersion>4.0.0</modelVersion>
  11. <artifactId>cloude-eureka-server7001</artifactId>
  12. <dependencies>
  13. <!--eureka-server-->
  14. <dependency>
  15. <groupId>org.springframework.cloud</groupId>
  16. <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
  17. </dependency>
  18. <!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
  19. <dependency>
  20. <groupId>org.example</groupId>
  21. <artifactId>springcloud-api-common</artifactId>
  22. <version>1.0-SNAPSHOT</version>
  23. </dependency>
  24. <!--boot web actuator-->
  25. <dependency>
  26. <groupId>org.springframework.boot</groupId>
  27. <artifactId>spring-boot-starter-web</artifactId>
  28. </dependency>
  29. <dependency>
  30. <groupId>org.springframework.boot</groupId>
  31. <artifactId>spring-boot-starter-actuator</artifactId>
  32. </dependency>
  33. <!--一般通用配置-->
  34. <dependency>
  35. <groupId>org.springframework.boot</groupId>
  36. <artifactId>spring-boot-devtools</artifactId>
  37. <scope>runtime</scope>
  38. <optional>true</optional>
  39. </dependency>
  40. <dependency>
  41. <groupId>org.projectlombok</groupId>
  42. <artifactId>lombok</artifactId>
  43. </dependency>
  44. <dependency>
  45. <groupId>org.springframework.boot</groupId>
  46. <artifactId>spring-boot-starter-test</artifactId>
  47. <scope>test</scope>
  48. </dependency>
  49. <dependency>
  50. <groupId>junit</groupId>
  51. <artifactId>junit</artifactId>
  52. </dependency>
  53. </dependencies>
  54. </project>

2、YML

  1. server:
  2. port: 7001
  3. eureka:
  4. instance:
  5. hostname: locathost #eureka服务端的实例名称
  6. client:
  7. #false表示不向注册中心注册自己。
  8. register-with-eureka: false
  9. #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
  10. fetch-registry: false
  11. service-url:
  12. #设置与Eureka server交互的地址查询服务和注册服务都需要依赖这个地址。
  13. defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

3、启动类

  1. package com.learn.springcloud;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
  5. @SpringBootApplication
  6. @EnableEurekaServer
  7. public class EurekaMain7001 {
  8. public static void main(String[] args) {
  9. SpringApplication.run(EurekaMain7001.class,args);
  10. }
  11. }

运行结果
image.png

将支付模块和消费模块都加入到EurekaServer中

1、POM

导入依赖

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

2、YML文件

  1. eureka:
  2. client:
  3. #表示是否将自己注册进Eurekaserver默认为true。
  4. register-with-eureka: true
  5. #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
  6. fetchRegistry: true
  7. service-url:
  8. defaultZone: http://localhost:7001/eureka

3、启动类

添加上EnableEurekaClient注解

  1. @SpringBootApplication
  2. @EnableEurekaClient
  3. public class Payment8001 {
  4. public static void main(String[] args) {
  5. SpringApplication.run(Payment8001.class,args);
  6. }
  7. }

结果
image.png

Eureka集成

  • 找到C:\Windows\System32\drivers\etc路径下的hosts文件,修改映射配置添加进hosts文件

    127.0.0.1 eureka7001.com 127.0.0.1 eureka7002.com

  • 修改cloud-eureka-server7001配置文件 ```xml server: port: 7001

eureka: instance: hostname: eureka7001.com #eureka服务端的实例名称 client: register-with-eureka: false #false表示不向注册中心注册自己。 fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务 service-url:

  1. #集群指向其它eureka
  2. defaultZone: http://eureka7002.com:7002/eureka/
  3. #单机就是7001自己
  4. #defaultZone: http://eureka7001.com:7001/eureka/
  1. - 修改cloud-eureka-server7002配置文件
  2. ```xml
  3. server:
  4. port: 7002
  5. eureka:
  6. instance:
  7. hostname: eureka7002.com #eureka服务端的实例名称
  8. client:
  9. register-with-eureka: false #false表示不向注册中心注册自己。
  10. fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
  11. service-url:
  12. #集群指向其它eureka
  13. defaultZone: http://eureka7001.com:7001/eureka/
  14. #单机就是7002自己
  15. #defaultZone: http://eureka7002.com:7002/eureka/

支付订单集成

  • 将支付服务8001微服务,订单服务80微服务发布到上面2台Eureka集群配置中

将它们的配置文件的eureka.client.service-url.defaultZone进行修改

  1. eureka:
  2. client:
  3. #表示是否将自己注册进Eurekaserver默认为true。
  4. register-with-eureka: true
  5. #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
  6. fetchRegistry: true
  7. service-url:
  8. defaultZone: http://eureka7001.com:7001/eureka, http://eureka7002.com:7002/eureka

Euraka保护机制

自我保护机制是 Eureka 注册中心的重要特性,当 Eureka 注册中心进入自我保护模式时,在 Eureka Server 首页会输出如下警告信息:

EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE
在没有 Eureka 自我保护的情况下,如果 Eureka Server 在一定时间内没有接收到某个微服务实例的心跳,Eureka Server 将会注销该实例。即使微服务实际是正常的,只是因为可能网络不好导致接收心跳较慢。
自我保护模式的工作机制是:如果在短时间内有过多的客户端节点都没有正常的心跳,那么 Eureka 就认为客户端与注册中心出现了网络故障,Eureka Server自动进入自我保护模式;当网络故障恢复后,Eureka Server会自动退出自我保护模式。

在自我保护模式下:

  1. Eureka Server不再从注册列表中移除心跳不正常的服务。
  2. Eureka Server仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上,保证当前节点依然可用。
  3. 当网络稳定时,当前 Eureka Server中新的注册信息会被同步到其它节点中。