1、微服务架构

1、概述

  • 微服务架构是种架构模式, 它提倡将单一应用程序划分成一组小的服务, 服务之间互相协调、互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务与服务间采用轻量级的通信机制互相协作(通常是基于HTTP协议的RESTful API) 。每个服务都围绕着具本业务进行构建,并且能够被独立的部署到生产环境、类生产环境等。另外,应当尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建

image.png
image.png
image.png
image.png

2、SpringColoud

SpringCloud=分布式微服务架构的一站式解决方案,是多种微服务架构落地技术的集合体,俗称微服务全家桶服猜猜SpringCloud这个大集合里有多少种技术?
image.png
image.png
image.png
image.png
image.pngimage.png

3、SpringCloud技术栈

image.png

  • 主要讲7种

image.png

4、总结

image.png

2、从2.2.x和H版开始说起

1、SpringCloud第2季分为上半场和下半场

4、微服务架构编码构建

1、IDEA新建project工作空间

1、微服务cloud整体聚合父工程Project创建父工程

1、根据maven的模板创建 maven-archetype-site

image.png

2、设置包名,项目名称

image.png

3、选择本地自己安装的maven

image.png

4、创建完父工程

  • 删除没用的src

image.png

5、配置idea环境

  • 编码utf-8

image.png

6、注解激活生效

image.png

7、选择Java8

image.png

8、文件过滤

看看想什么过滤掉的就过滤掉

  1. *.hprof;*.idea;*.pyc;*.pyo;*.rbc;*.yarb;*iml;*~;.DS_Store;.git;.hg;.svn;CVS;__pycache__;_svn;vssver.scc;vssver2.scc;

image.png

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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.daijunyi</groupId>
  <artifactId>cloud2020</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>pom</packaging>

  <!-- 统一管理jar包版本 -->
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <junit.version>4.12</junit.version>
    <log4j.version>1.2.17</log4j.version>
    <lombok.version>1.16.18</lombok.version>
    <mysql.version>5.1.47</mysql.version>
    <druid.version>1.1.16</druid.version>
    <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
  </properties>
  <!-- 子模块继承之后,提供作用:锁定版本+子modlue不用写groupId和version  -->
  <dependencyManagement>
    <dependencies>
      <!--spring boot 2.2.2-->
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId >spring-boot-dependencies</artifactId >
        <version >2.2.2.RELEASE</version >
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <!--spring cloud Hoxton.SR1-->
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId >spring-cloud-dependencies</artifactId >
        <version >Hoxton.SR1</version >
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <!--spring cloud alibaba 2.1.0.RELEASE-->
      <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId >spring-cloud-alibaba-dependencies</artifactId >
        <version >2.1.0.RELEASE</version >
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>${mysql.version}</version>
      </dependency>
      <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>${druid.version}</version>
      </dependency>
      <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>${mybatis.spring.boot.version}</version>
      </dependency>
      <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>${junit.version}</version>
      </dependency>
      <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>${log4j.version}</version>
      </dependency>
      <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>${lombok.version}</version>
        <optional>true</optional>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>2.2.2.RELEASE</version>
        <configuration>
          <fork>true</fork>
          <addResources>true</addResources>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

3、Maven细节

1、Maven中的DependencyManagement和Dependencies

  • dependencyManagement
    • Maven 使用dependencyManagement 元素来提供了一种管理依赖版本号的方式。
    • 通常会在一个组织或者项目的最顶层的父POM 中看到dependencyManagement 元素。
    • 使用pom.xml 中的dependencyManagement 元素能让所有在子项目中引用一个依赖而不用显式的列出版本号。 Maven 会沿着父子层次向上走,直到找到一个拥有dependencyManagement 元素的项目,然后它就会使用这个 dependencyManagement 元素中指定的版本号。

image.png
image.png
这样做的好处就是:如果有多个子项目都引用同一样依赖,则可以避免在每个使用的子项目里都声明一个版本号,这样当想升级或切换到另一个版本时,只需要在顶层父容器里更新,而不需要一个一个子项目的修改;另外如果某个子项目需要另外的一个版本,只需要声明version就可。

  • dependencyManagement里只是声明依赖,并不实现引入,因此子项目需要显示的声明需要用的依赖。
  • 如果不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目中写了该依赖项,并且没有指定具体版本, 才会从父项目中继承该项,并且version和scope都读取自父pom;
  • 如果子项目中指定了版本号,那么会使用子项目中指定的jar版本。

    2、maven中跳过单元测试

    配置

    <build> <!-- maven 中跳过单元测试  -->
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-surefire-plugin</artifactId>
          <configuration>
            <skip>true</skip>
          </configuration>
        </plugin>
      </plugins>
    </build>
    

    idea插件配置
    image.png
    4、父工程创建完成执行mvn:install将父工程发布到仓库方便子工程继承
    image.png

    4、mysql驱动说明

  • com.mysql.jdbc.Driver和mysql-connector-java 5一起用。

  • com.mysql.cj.jdbc.Driver和mysql-connector-java 6 一起用。
  • com.mysql.cj.jdbc.Driver是mysql-connector-java 6 中的特性,相比mysql-connector-java 5 多了一个时区:serverTimezone,把数据源配置的驱动改一下就好了
  • org.gjt.mm.mysql.Driver是当时最好的MySQL JDBC,但不是MySQL公司的,然后MySQL将MM的JDBC驱动收为官方的JDBC驱动,所以将驱动的package也改了,但还保留了org.gjt.mm.mysql.Driver这个路径的引用,也就是你使用新版的JDBC驱动时还可以通过这个来引用,打开下载的新版JDBC驱动的jar文件可以看到,只有一个文件的目录是org.gjt.mm.mysql,就是为了兼容而设计的。

    2、Rest微服务工程构建

    1、cloud-provider-payment8001微服务提供者支付Module模块

    1、建cloud-provider-payment8001

    image.png
    image.png

    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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    

      <artifactId>cloud2020</artifactId>
      <groupId>com.daijunyi</groupId>
      <version>1.0-SNAPSHOT</version>
    

    4.0.0 cloud-provider-payment8001 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-actuator org.mybatis.spring.boot mybatis-spring-boot-starter com.alibaba druid-spring-boot-starter 1.1.10 mysql mysql-connector-java org.springframework.boot spring-boot-starter-jdbc org.springframework.boot spring-boot-devtools runtime true org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test

<a name="TpKyg"></a>
#### 3、写YML
```yaml
server:
  port: 8001

spring:
  application:
    name: cloud-payment-service
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
    driver-class-name: com.mysql.cj.jdbc.Driver           # mysql驱动包 com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/learn?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: qwerasdf123

mybatis:
  mapperLocations: classpath:mapper/*.xml
  type-aliases-package: com.daijunyi.entities    # 所有Entity别名类所在包

4、主启动

package com.daijunyi;

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

@SpringBootApplication
public class PaymentMain8001 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain8001.class);
    }
}

5、业务类

(1)键表

  CREATE TABLE `payment` ( 
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', 
  `serial` varchar(200) DEFAULT '', 
  PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8

(2)创建实体类

  • Payment ```java package com.daijunyi.entities;

import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString;

import java.io.Serializable;

@ToString @Data @NoArgsConstructor @AllArgsConstructor public class Payment implements Serializable {

private static final long serialVersionUID = 5494040778539765191L;
private Long id;
private String serial;

}


- CommonResult
```java
package com.daijunyi.entities;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult<T>
{
    private Integer code;
    private String  message;
    private T data;

    public CommonResult(Integer code, String message)
    {
        this(code,message,null);
    }
}

(3)dao

  • PaymentDao ```java package com.daijunyi.dao;

import com.daijunyi.entities.Payment; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param;

@Mapper //import org.apache.ibatis.annotations.Mapper; public interface PaymentDao { public int create(Payment payment);

public Payment getPaymentById(@Param("id" ) Long id);

}


- 在resources下创建mapper文件夹,并添加文件PaymentMapper.xml
```xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.daijunyi.dao.PaymentDao">

    <resultMap id="BaseResultMap" type="com.daijunyi.entities.Payment">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <result column="serial" property="serial" jdbcType="VARCHAR"/>
    </resultMap>

    <insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO payment(SERIAL) VALUES(#{serial});
    </insert>

    <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
        SELECT *  FROM payment WHERE id=#{id};
    </select>
</mapper>

(4)service

  • 创建paymentService接口 ```java package com.daijunyi.service;

import com.daijunyi.entities.Payment; import org.apache.ibatis.annotations.Param;

public interface PaymentService { public int create(Payment payment); public Payment getPaymentById(@Param(“id”) Long id); }


- 实现类PaymentServiceImpl
```java
package com.daijunyi.service.imp;

import com.daijunyi.dao.PaymentDao;
import com.daijunyi.entities.Payment;
import com.daijunyi.service.PaymentService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class PaymentServiceImpl implements PaymentService {
    @Resource
    private PaymentDao paymentDao;

    @Override
    public int create(Payment payment) {
        return paymentDao.create(payment);
    }

    @Override
    public Payment getPaymentById(Long id) {
        return paymentDao.getPaymentById(id);
    }
}

(5)controller
创建PaymentController

package com.daijunyi.controller;

import com.daijunyi.entities.CommonResult;
import com.daijunyi.entities.Payment;
import com.daijunyi.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

@RestController
@Slf4j
public class PaymentController {
    @Resource
    private PaymentService paymentService;

    @PostMapping(value = "/payment/create")
    public CommonResult create(@RequestBody Payment payment) {
        int result = paymentService.create(payment);
        log.info("*****插入操作返回结果:" + result);

        if (result > 0) {
            return new CommonResult(200, "插入数据库成功", result);
        } else {
            return new CommonResult(444, "插入数据库失败", null);
        }
    }

    @GetMapping(value = "/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
        Payment payment = paymentService.getPaymentById(id);
        log.info("*****查询结果:{}", payment);
        if (payment != null) {
            return new CommonResult(200, "查询成功", payment);
        } else {
            return new CommonResult(444, "没有对应记录,查询ID: " + id, null);
        }
    }
}

6、测试

(1)测试请求

  • 数据库自己添加点数据

http://localhost:8001//payment/get/1
(2)postman测试创建
(3)运行

7、小总结

  • (1)建module
  • (2)改pom
  • (3)写YML
  • (4)主启动类
  • (5)业务类

    2、热部署Devtools

    1、添加devtools到具体的project

    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
    </dependency>
    

    2、添加plugin到父pom.xml

    <build>
    <!--finalName 可以不添加-->
    <finalName>cloud2020</finalName>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>2.2.2.RELEASE</version>
        <configuration>
          <fork>true</fork>
          <addResources>true</addResources>
        </configuration>
      </plugin>
    </build>
    

    3、Enabling automatic build

    image.png

    4、Update the value of

  • 在我们的8001工程中

    • mac:快捷键comand+option+shift+/
    • windos: 快捷键ctry+alt+shift+/

image.png
image.png

5、重启idea

  • 重启之后只要在文件编辑发生了变化,idea就会重新部署代码了

    3、cloud-consumer-order80微服务消费者订单Module模块

    (1)创建cloud-consumer-order80项目

    image.png

    (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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    

      <artifactId>cloud2020</artifactId>
      <groupId>com.daijunyi</groupId>
      <version>1.0-SNAPSHOT</version>
    

    4.0.0 cloud-consumer-order80
<dependencies>
    <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>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

<a name="FZr1I"></a>
#### (3)创建yaml配置文件
```yaml
server:
  port: 80

(4)创建启动类

package com.daijunyi;

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

@SpringBootApplication
public class MainConsumerOrderAppliction80 {

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

(5)写主业务代码

  • entities
    • 复制8001中的
    • image.png
  • config ```java package com.daijunyi.config;

import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate;

@Configuration public class ApplicationContextConfig {

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

}


- controller
```java
package com.daijunyi.controller;

import com.daijunyi.entities.CommonResult;
import com.daijunyi.entities.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

@RestController
@Slf4j
public class OrderController {

    public static final String PAYMENT_URL = "http://localhost:8001";

    @Autowired
    private RestTemplate restTemplate;

    @PostMapping("/consumer/payment/create")
    public CommonResult<Payment> create(Payment payment){
        return restTemplate.postForObject(PAYMENT_URL+"/payment/create",payment,CommonResult.class);
    }

    @GetMapping("/consumer/payment/get/{id}")
    public CommonResult<Payment> getPayment(@PathVariable Long id){
        return restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);
    }
}
  • 测试

    • image.png

      (6)介绍RestTemplate

  • RestTemplate提供了多种便捷访问远程Http服务的方法,是一种简单便捷的访问restful服务模板类,是Spring提供的用于访问Rest服务的客户端模板工具集

  • 官网地址
  • 使用

    • 使用restTemplate访问restful接口非常的简单粗暴无脑。 (url, requestMap, ResponseBean.class)这三个参数分别代表 REST请求地址、请求参数、HTTP响应转换被转换成的对象类型。

      4、工程重构

      1、创建cloud-api-commons工程

      image.png

      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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      

      cloud2020 com.daijunyi 1.0-SNAPSHOT 4.0.0 cloud-api-commons org.springframework.boot spring-boot-devtools runtime true org.projectlombok lombok true cn.hutool hutool-all 5.1.0

<a name="DhCEy"></a>
#### 3、把entities复制到工程下
![image.png](https://cdn.nlark.com/yuque/0/2021/png/12971636/1630249512003-eb19ddb2-acd5-4fee-9520-21040feb4c42.png#clientId=u8dbbdf0e-4028-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=389&id=uf5ed7de2&margin=%5Bobject%20Object%5D&name=image.png&originHeight=778&originWidth=2224&originalType=binary&ratio=1&rotation=0&showTitle=false&size=196379&status=done&style=none&taskId=u3cfb7619-6872-4a59-89ba-6aa9dcaf09c&title=&width=1112)
<a name="qirX5"></a>
#### 4、maven install 安装到本地库
<a name="X8iwO"></a>
#### 5、删除8001和80项目的entities
<a name="BHYb5"></a>
#### 6、引入cloud-api-commons的包到8001和80下,各自添加pom文件修改
```xml
<dependency>
  <groupId>com.daijunyi</groupId>
  <artifactId>cloud-api-commons</artifactId>
  <version>${project.version}</version>
</dependency>

5、目前工程样图

image.png

6、Run Dashboard

  • 通过修改idea的workspace.xml的方式来快速打开Run Dashboard窗口
  • 添加如下配置
    <component name="RunDashboard">
      <option name="configurationTypes">
        <set>
          <option value="SpringBootApplicationConfigurationType" />
        </set>
      </option>
    </component>