分类 Paas 下的文章

目录


环境介绍#

技术选型SpringCloud&SpringCloud Alibaba&Docker

微服务模块划分

  1. 员工模块:ems-employees

  2. 部门模块:ems-departments

  3. 网关模块:ems-gateway

  4. 公共模块:ems-commons

其他环境

Mysql8.0+、nacos1.3+、JDK1.8

前置准备知识

SpringCloudSpringCloud alibabaDockerDocker-ComposeDockerfile

数据库结构:

一个部门表和一个员工表,员工表里面有个部门ID和部门表主键相关联

数据库sql脚本

use emsSET NAMES utf8mb4;SET FOREIGN_KEY_CHECKS = 0;-- ------------------------------ Table structure for department-- ----------------------------DROP TABLE IF EXISTS `department`;CREATE TABLE `department` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(80) DEFAULT NULL COMMENT '部门名称',
  `created_at` datetime DEFAULT NULL COMMENT '创建时间',  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ------------------------------ Table structure for employee-- ----------------------------DROP TABLE IF EXISTS `employee`;CREATE TABLE `employee` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(40) DEFAULT NULL,
  `birthday` datetime DEFAULT NULL COMMENT '生日',
  `salary` double(10,2) DEFAULT NULL COMMENT '工资',
  `department_id` int(11) DEFAULT NULL COMMENT '部门信息',  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;SET FOREIGN_KEY_CHECKS = 1;

部署流程#

  1. 先在服务器安装Docker,然后在Docker中安装mysql、nacos镜像,并启动容器

  2. 在员工、部门等微服务模块中指定nacos注册中心地址,使服务注册进去

  3. 把springcloud微服务模块打包成jar包上传至服务器,然后通过Dockerfile构建成镜像

  4. 最后通过docker-compose构建编排项目,将这些微服务镜像打包成一整个项目并启动

环境搭建#

1.Centos7.X安装Docker

网上操作教程很多,略

2.Docker安装mysql、nacos镜像

2.1 安装mysql

1、没有指定版本一般安装的都是最新的8.0+

docker pull mysql

2、docker启动mysql,简单演示就没有创建数据卷了

docker run --name=mysql01 -it -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql

3、启动成功

image-20220102180005212

4、进入mysql容器

docker exec -it  mysql01 /bin/bash

5、登陆mysql

mysql -u root -p

6、授权所有用户可以登录

GRANT ALL PRIVILEGES ON *.* TO 'root'@'%'WITH GRANT OPTION;

7、刷新权限  

FLUSH PRIVILEGES;

8、使用客户端连接

image-20220102183304777

2.2 安装nacos
docker pull nacos/nacos-server:1.3.0

1、运行nacos

docker run  --name nacos-quick -e  MODE=standalone -p 8848:8848 -d nacos/nacos-server:1.3.0

2、查看nacos运行日志

docker logs -f b1aacab47d2a

image-20220102184603996

表示启动成功

3、访问成功

image-20220102184738169

默认用户名登录密码都是nacos

3.搭建SpringCloud微服务模块

3.1 搭建父工程模块

image-20220103104841235

image-20220103104929409

image-20220103105150507

父工程的必须遵循以下两点要求:

1.父工程的 packaging 标签的文本内容必须设置为 pom,如果不指定会默认打包成jar包

2.删除src目录

image-20220103105323383

搭建父工程的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>com.ylc</groupId>
    <artifactId>springcloud-dockerDemo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <mysql.version>8.0.23</mysql.version>
        <spring.cloud.version>Hoxton.SR1</spring.cloud.version>
        <spring.cloud.alibaba.version>2.2.0.RELEASE</spring.cloud.alibaba.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!--spring cloud Hoxton.SR1-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud.version}</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>${spring.cloud.alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build></project>
3.2 搭建员工子模块

image-20220103105744331

image-20220103105854905

点击下一步最后完成

image-20220103110016595

删除一些没用的文件HELP.md、MVNW等等,修改子项目的 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>

    <!-- 确认继承关系 -->
    <parent>
        <!--父工程 gropuId-->
        <groupId>com.ylc</groupId>
        <!--父工程 artifactId-->
        <artifactId>springcloud-dockerDemo</artifactId>
        <!--父工程 版本-->
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>ems-employess</artifactId>

    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--nacos-service-discovery-client-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--druid mysql mybatis-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.6</version>
        </dependency>
        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.23</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.0</version>
        </dependency>
        <!--远程调用openfegin-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.10.1</version>
            <scope>compile</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>

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

在父工程 pom.xml 中 添加子模块标识

image-20220103110152948

开启服务注册中心nacos,并开启远程调用

@EnableFeignClients@EnableDiscoveryClient@SpringBootApplicationpublic class EmsEmploysApplication {    public static void main(String[] args) {
        SpringApplication.run(EmsEmploysApplication.class, args);
    }
}

然后在配置文件application.properties配置nacos的参数、以及数据源配置

server.port=8085spring.application.name=DEPARTMENTSspring.cloud.nacos.server-addr=xxx:8848# datasourcespring.datasource.type=com.alibaba.druid.pool.DruidDataSourcespring.datasource.driver-class-name=com.mysql.cj.jdbc.Driverspring.datasource.url=jdbc:mysql://xxxx:3306/ems?useSSL=false&characterEncoding=UTF-8spring.datasource.username=rootspring.datasource.password=123456# mybatismybatis.type-aliases-package=com.ylc.entitymybatis.mapper-locations=classpath:com/ylc/mapper/*.xml# loglogging.level.com.ylc=debug

bootstrap.properties中配置nacos

spring.cloud.nacos.config.server-addr=121.43.33.150:8848spring.cloud.nacos.discovery.server-addr=121.43.33.150:8848

在idea中远程连接mysql

image-20220103160733218

然后利用idea中安装的插件Easycode,根据表去生成service、controller、dao、mapper相关代码

点击这个

image-20220103162655774

module代表生成的模块

package:包名

path:生成的路径

image-20220103163437305

最后生成成功

image-20220103163630949

其中有分页部分爆红的方法,删掉就行了,只简单演示

然后记得添加相关注解@Mapper、@Service、@Repository等等

访问成功

image-20220103181039770

3.3 搭建部门子模块

按照上一个模块流程搭建,pom文件也是相同的,端口改为8086

访问成功

image-20220103183405568

3.4 抽取公共模块

上面两个微服务会有重复代码,抽取公共部分包含项目一些公共的类以及jar包

Department

package com.ylc;import java.io.Serializable;import java.util.Date;/**
 * @author yanglingcong
 * 部门类
 */public class Department implements Serializable {    private static final long serialVersionUID = 279210942586979318L;    private Integer id;    /**
     * 部门名称
     */
    private String name;    /**
     * 创建时间
     */
    private Date createdAt;    private Employee employee;    public Employee getEmployee() {        return employee;
    }    public void setEmployee(Employee employee) {        this.employee = employee;
    }    public Integer getId() {        return id;
    }    public void setId(Integer id) {        this.id = id;
    }    public String getName() {        return name;
    }    public void setName(String name) {        this.name = name;
    }    public Date getCreatedAt() {        return createdAt;
    }    public void setCreatedAt(Date createdAt) {        this.createdAt = createdAt;
    }
}

Employee

package com.ylc;import com.fasterxml.jackson.annotation.JsonProperty;import java.io.Serializable;import java.util.Date;/**
 * (Employee)实体类
 * @author yanglingcong
 */public class Employee implements Serializable {    private static final long serialVersionUID = -87055454147065054L;    private String id;    private String name;    /**
     * 生日
     */
    private Date birthday;    /**
     * 工资
     */
    private String salary;    /**
     * 部门信息
     */
    @JsonProperty("department_id")
    private Integer departmentId;    private Department department;    public Department getDepartment() {        return department;
    }    public void setDepartment(Department department) {        this.department = department;
    }    public String getId() {        return id;
    }    public void setId(String id) {        this.id = id;
    }    public String getName() {        return name;
    }    public void setName(String name) {        this.name = name;
    }    public Date getBirthday() {        return birthday;
    }    public void setBirthday(Date birthday) {        this.birthday = birthday;
    }    public String getSalary() {        return salary;
    }    public void setSalary(String salary) {        this.salary = salary;
    }    public Integer getDepartmentId() {        return departmentId;
    }    public void setDepartmentId(Integer departmentId) {        this.departmentId = departmentId;
    }
}

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

    <!-- 确认继承关系 -->
    <parent>
        <!--父工程 gropuId-->
        <groupId>com.ylc</groupId>
        <!--父工程 artifactId-->
        <artifactId>springcloud-dockerDemo</artifactId>
        <!--父工程 版本-->
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>ems-employess</artifactId>

    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--nacos-service-discovery-client-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--druid mysql mybatis-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.6</version>
        </dependency>
        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.23</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.0</version>
        </dependency>
        <!--远程调用openfegin-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.10.1</version>
            <scope>compile</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>

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

公共模块搭建很简单就两个类,然后在其他模块引用公共模块

 <dependencies>
        <!--公共模块-->
        <dependency>
            <groupId>com.ylc</groupId>
            <artifactId>ems-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

到此就完成了

3.5.测试

通过查询员工信息,然后远程调用部门信息

远程接口

@FeignClient("DEPARTMENTS")public interface DepartmentClient {    //部门详细
    @GetMapping("/department/{id}")
     Department detail(@PathVariable("id") Integer id);
}

1、接口定义

/**
 *  查询员工以及部门的详细信息
 * @return List<Employee>
 */

 List<Employee> queryAll();

2、实现类

@Overridepublic List<Employee> queryAll() {
    List<Employee> employees=employeeDao.queryAll();
    employees.forEach(emp->{
        Integer departmentid=emp.getDepartmentId();        Department detail = departmentClient.detail(departmentid);
        emp.setDepartment(detail);
    });    return employees;
}

3、调用方法

    //员工列表
    @GetMapping
    public List<Employee> employees() {        return employeeService.queryAll();
    }

4、测试localhost:8085/employee

image-20220103195635159

3.6 搭建网关子模块

image-20220103201046959

1、开启服务注册发现

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

2、网关配置

image-20220103220634321

spring:
  cloud:
    gateway:
      routes: # 用来配置网关路由规则
        - id: employee_route
          uri: lb://EMPLOYESS
          predicates:
            - Path=/ems/employee
          filters:
            - StripPrefix=1

        - id: department_route
          uri: lb://DEPARTMENTS
          predicates:
            - Path=/ems/department
          filters:
            - StripPrefix=1

3、bootstrap.yml

server.port=8888spring.application.name=GATEWAYspring.cloud.nacos.server-addr=121.43.33.150:8848spring.cloud.nacos.config.server-addr=121.43.33.150:8848spring.cloud.nacos.discovery.server-addr=121.43.33.150:8848spring.cloud.nacos.config.enabled=false

4、通过网关访问成功

image-20220103220426218

至此整个项目流程就打通了

部署#

1.本地测试

1、打包之前每个项目都需要有springboot的打包插件,没有的话要在项目中引入

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

安装之后出现这个就可以了

image-20220103221640922

2、先对父项目进行清理(clean)再打包(Package),common公共模块是没主启动类的,这时候把父项目的pom文件的该插件注释调就行了。

   <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

全部打包完成

image-20220103221818398

3、先在本地测试jar是否成功

运行员工模块

image-20220103222146017

运行部门模块

image-20220103222411533

运行网关模块

image-20220103222437716

都成功之后本地访问http://localhost:8888/ems/employee

到这里都没有问题说明本地测试通过了

2.编写Dockerfile

docker中需要有JDK1.8的镜像,安装JDK

docker pull openjdk:8

image-20220103223207189

在idea中编写员工模块Dockerfile

image-20220103225314017

FROM openjdk:8ENV APP_HOME=/appsWORKDIR $APP_HOMECOPY ./ems-employess-1.0-SNAPSHOT.jar ./employess.jarEXPOSE 8086ENTRYPOINT ["java","-jar"]CMD ["employess.jar"]

部门模块Dockerfile

FROM openjdk:8ENV APP_HOME=/appsWORKDIR $APP_HOMECOPY ./ems-departments-0.0.1-SNAPSHOT.jar ./departments.jarEXPOSE 8085ENTRYPOINT ["java","-jar"]CMD ["departments.jar"]

网关模块Dockerfile

FROM openjdk:8ENV APP_HOME=/appsWORKDIR $APP_HOMECOPY ./ems-gateway-1.0-SNAPSHOT.jar ./gateway.jarEXPOSE 8888ENTRYPOINT ["java","-jar"]CMD ["gateway.jar"]

然后在idea 中登录docker所在服务器

image-20220103225516099

3.Dockerfile文件上传

然后把项目的文件上传到服务自己建的ems文件夹中

image-20220103230243686

4.编写docker-compose.yml

直接利用dockerfile文件的路径打包成镜像,最后编排运行

version: "3.8"networks:
  ems:volumes:
  data:services:

  employee:
    build:
      context: ./employee
      dockerfile: Dockerfile
    ports:
      - "8085:8085"
    networks:
      - ems

  department:
    build:
      context: ./department
      dockerfile: Dockerfile
    ports:
      - "8086:8086"
    networks:
      - ems

  gateway:
    build:
      context: ./gateway
      dockerfile: Dockerfile
    ports:
      - "8888:8888"
    networks:
      - ems

  nacos:
    image: nacos/nacos-server:1.3.1
    ports:
      - "8848:8848"
    environment:
      - "MODE=standalone"
    networks:
      - ems


  mysql:
    image: mysql
    ports:
      - "3306:3306" #只写一个端口随机使用宿主机一个端口进行容器端口映射
    environment:
      - "MYSQL_ROOT_PASSWORD=root"
      - "MYSQL_DATABASE=ems"
    volumes:
      - data:/var/lib/mysql
      #- ./ems.sql:/docker-entrypoint-initdb.d/ems.sql
    networks:
      - ems

5.项目启动

在服务器ems文件夹中输入

docker-compose up -d department
docker-compose up -d employee
docker-compose up -d gateway

image-20220103231213593

报错

有个服务报错:Error: Invalid or corrupt jarfile employess.jar

image-20220104001204222

检查了好几遍,重新打包上传还是这样,最后进目录查看发现jar包每次都没有上传完整

image-20220104001321050

文件大小明显不对,因为打包错了里面没有主启动类,我在打包之前就删除这些,添加进来然后重新运行 mvn install即可

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

这下正常了

image-20220104002539137

再次运行因为之前构建的镜像还在,即便重新上传还是运行的之前构建的,没有效果,所以的删除之前构建过的错误镜像,三个都运行成功

image-20220104003902487

部署成功!

image-20220104004009904

总结#

还有很多可以优化的地方,因为本节是着重演示部署流程,细节方面就没有优化了

这就是一整个部署的大概流程,但每次项目代码如果有更改,又需要手动重新生成镜像然后在服务器重新运行,还是不太方便,后续会出Jenkins+Docker自动化部署SpringCloud,实现代码提交自动进行编译打包上传并部署,简化在部署方面的操作。

项目细节难免有纰漏之处,附项目地址:https://gitee.com/yanglingcong/spring-cloud-docker


bus组件:实现远端配置修改自动刷新


实现自动配置刷新

MQ服务主机:47.106.105.80:15672
MQ端口号:15672(web管理界面) 5672(Java)
虚拟主机:ems

1、在springcloud-config-server-3344config服务端引入依赖

<!--引入bus依赖--><dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-bus-amqp</artifactId></dependency>

2、配置config Server配置文件,通过bus连接MQ的配置

server:
  port: 3344spring:
  application:
    name: springcloud-config-server
  # 连接码云远程仓库
  cloud:
    config:
      server:
        git:
          # 注意是https的而不是ssh
          uri: https://gitee.com/luoxiao1104/springcloud-config.git
          # 通过 config-server可以连接到git,访问其中的资源以及配置~
          default-label: master
  #通过bus组件连接到MQ服务
  rabbitmq:
    host: 47.106.105.80 #连接主机
    port: 5672 #连接mq端口
    username: guest #连接mq用户名
    password: guest #连接mq密码
    virtual-host: /#Eureka配置,服务注册到哪里eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: springcloud-cofig-server-3344  #修改Eureka默认描述信息

启动springcloud-config-server-3344config服务端查看
image

3、配置微服务config client通过bus连接MQ服务

a.在所有微服务项目中(springcloud-config-client-3355)引入Bus依赖

<!--引入bus依赖--><dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-bus-amqp</artifactId></dependency>

b.在所有的微服务项目中配置MQ配置,即配置远端的配置文件
注意这个bootstrap的配置并不是最终配置,需要通过这里面的配置拉取远端的配置,获取远端配置启动,因此需要将这段配置放入远端的仓库进行管理
image
c.在config客户端bootstrap.yaml添加下面配置
image
d.启动springcloud-config-client-3355config客户端
image
4、在springcloud-config-server-3344config服务中配置application.yaml暴露所有端点
image

现在消息总线和config连接到一起,以后只需要在config Server发一次POST请求,所有的config client配置文件都会发生改变。

指定服务刷新配置实现

集成webhook实现自动刷新

webhooks
根据远程仓库触发对应事件发送一个web请求默认就是POST方式请求

一、在远端仓库中配置webhooks

1、在springcloud-config-server-3344config服务器中添加过滤器(必须要添加,不然后面配置webhooks会报错)

package com.study.springcloud.filters;import org.springframework.stereotype.Component;import javax.servlet.*;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletRequestWrapper;import javax.servlet.http.HttpServletResponse;import java.io.BufferedReader;import java.io.ByteArrayInputStream;import java.io.IOException;@Componentpublic class UrlFilter  implements Filter {    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
 
    } 
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {        HttpServletRequest httpServletRequest = (HttpServletRequest)request;        HttpServletResponse httpServletResponse = (HttpServletResponse)response; 
        String url = new String(httpServletRequest.getRequestURI()); 
        //只过滤/actuator/bus-refresh请求
        if (!url.endsWith("/bus-refresh")) {
            chain.doFilter(request, response);            return;
        } 
        //获取原始的body
        String body = readAsChars(httpServletRequest);
 
        System.out.println("original body:   "+ body); 
        //使用HttpServletRequest包装原始请求达到修改post请求中body内容的目的
        CustometRequestWrapper requestWrapper = new CustometRequestWrapper(httpServletRequest);
 
        chain.doFilter(requestWrapper, response);
 
    } 
    @Override
    public void destroy() {
 
    } 
    private class CustometRequestWrapper extends HttpServletRequestWrapper {        public CustometRequestWrapper(HttpServletRequest request) {            super(request);
        } 
        @Override
        public ServletInputStream getInputStream() throws IOException {            byte[] bytes = new byte[0];            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); 
            return new ServletInputStream() {                @Override
                public boolean isFinished() {                    return byteArrayInputStream.read() == -1 ? true:false;
                } 
                @Override
                public boolean isReady() {                    return false;
                } 
                @Override
                public void setReadListener(ReadListener readListener) {
 
                } 
                @Override
                public int read() throws IOException {                    return byteArrayInputStream.read();
                }
            };
        }
    } 
    public static String readAsChars(HttpServletRequest request)
    { 
        BufferedReader br = null;        StringBuilder sb = new StringBuilder("");        try
        {
            br = request.getReader();
            String str;            while ((str = br.readLine()) != null)
            {
                sb.append(str);
            }
            br.close();
        }        catch (IOException e)
        {
            e.printStackTrace();
        }        finally
        {            if (null != br)
            {                try
                {
                    br.close();
                }                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }        return sb.toString();
    }
}

2、在主启动类中添加扫描包注解
image
3、在Gitee仓库中点击管理,再点击webhooks,最后点击添加
image

4、借助内网穿透(把内网地址转化为公网地址)使用natapp https://natapp.cn/

  • a.访问官方网址

  • b.注册 & 实名认证

  • c.购买免费通道

  • d.配置隧道 ==>配置本地端口 config server端口 3344

  • e.下载客户端 antapp.exe

  • f.在cmd命令行打开 启动natapp 输入natapp --authoken=a2164bdbdfe99d11(自己的验证码)
    image

5、输入信息
image
6、添加成功
image

springclou集成webhook实现自动刷新完成!


bus组件:消息总线RabbitMQ安装


bus组件简介

spring cloud bus使用轻量级消息代理将分布式系统的节点连接起来。然后,可以使用它来广播状态更改(例如配置更改)或其他管理指令。AMQP和Kafka broker(中间件)实现包含在项目中。或者,在类路径上找到的任何spring cloud stream绑定器都可以作为传输使用。

bus称之为springcloud中消息总线,主要用来在微服务系统中实现远端配置更新时通过广播形式通知所有客户端刷新配置信息,避免手动重启服务的工作

作用:利用bus 广播特性当一个状态(配置文件)发生改变时通知到bus中所有服务节点更新当前状态(自动更新自身配置)

实现配置刷新原理

image

RabbitMQ安装

1、进入RabbitMQ官网下载环境和安装包:https://www.rabbitmq.com/install-rpm.html#downloads

image

2、把环境和安装包放到linux服务器的root文件夹下

image

3、输入rpm -ivh erlang-22.0.7-1.el7.x86_64.rpm安装RabbitMQ运行环境

image

4、输入yum install -y rabbitmq-server-3.7.18-1.el7.noarch.rpm安装RabbitMQ安装包(需要联网)

image
提示安装完成
image

5、输入yum install socat -y安装socat

6、输入systemctl enable rabbirmq-server设置RabbitMQ开机自启

7、查看RibbitMQ是否安装成功

image

注意:默认安装完成后配置文件模板在:/usr/share/doc/rabbitmq-server-3.7.18/rabbitmq.config.example目录中,需要将配置文件复制到/etc/rabbitmq/目录中,并修改名称为rabbitmq.config

8、复制配置文件

image

9、编辑RabbitMQ的配置文件

进入编辑
image
找到对应位置
image
修改,如果输入:wq 提示文件只读的话,输入:wq!即可
image

10、启动RabbitMQ的web管理界面

image

11、启动RabbitMQ服务

image

12、输入服务ip:15672进入 RabbitMQ web管理界面,与Java TPC通信的端口为:6572

image

13、输入账号:guest 密码:guest ,进入RabbitMQ管理界面

image

14、添加一个RabbitMQ的管理用户

image

15、添加管理的虚拟主机

1、点击Virtaul Hosts
image
2、输入 /ems ,点击Add virtual host
image
3、
image
4、退出到用户管理界面,点击ems
image
5、
image
6、
image

15、不同用户又不同交换机的类型

image


统一配置中心:config


Config组件简介

spring cloud config 为微服务架构中的微服务提供集中化的外部支持,配置服务器为各个不同微服务应用的所有环节提供了一个中心化的外部配置

config(配置)又称为 统一配置中心顾名思义,就是将配置统一管理,配置统一管理的好处是在日后大规模集群部署服务应用时相同的服务配置一致,日后再修改配置只需要统一修改全部同步,不需要一个一个服务手动维护。

spring cloud config 分为服务端客户端两部分。

服务端也称为 分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密,解密信息等访问接口。

客户端则是通过指定的配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息。配置服务器默认采用git来存储配置信息,这样就有助于对环境配置进行版本管理。并且可用通过git客户端工具来方便的管理和访问配置内容。

imge

spring cloud config 分布式配置中心能干嘛?

  • 集中式管理配置文件

  • 不同环境,不同配置,动态化的配置更新,分环境部署,比如 /dev /test /prod /beta /release

  • 运行期间动态调整配置,不再需要在每个服务部署的机器上编写配置文件,服务会向配置中心统一拉取配置自己的信息

  • 当配置发生变动时,服务不需要重启,即可感知到配置的变化,并应用新的配置

  • 将配置信息以REST接口的形式暴露

环境搭建

由于spring cloud config 默认使用git来存储配置文件 (也有其他方式,比如自持SVN 和本地文件),但是最推荐的还是git ,而且使用的是 http / https 访问的形式。

1、在码云上新建仓库

image

2、选择HTTPS连接,点击复制

image

3、新建一个config-server模块springcloud-config-server-3344

image

4、添加相关依赖

<dependencies>
    <!--config server统一配置中心-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-server</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency></dependencies>

5、编写application.yaml配置文件

server:
  port: 3344spring:
  application:
    name: springcloud-config-server
  # 连接码云远程仓库
  cloud:
    config:
      server:
        git:
          # 注意是https的而不是ssh
          uri: https://gitee.com/luoxiao1104/springcloud-config.git
          # 通过 config-server可以连接到git,访问其中的资源以及配置~
          default-label: master

6、编写主启动类

package com.study.springcloud;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.config.server.EnableConfigServer;@SpringBootApplication@EnableConfigServerpublic class ConfigServerApplication_3344 {    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication_3344.class,args);
    }
}

7、启动主启动类测试是否成功

image

Config客户端开发-远程连接

config client :微服务

1、新建一个config客户端模块springcloud-config-client-3355

image

2、导入相关依赖

    <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.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>

3、编写application.yaml配置文件

server:
  port: 3355spring:
  application:
    name: springcloud-config-client#Eureka配置,服务注册到哪里eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: springcloud-cofig-client-3355  #修改Eureka默认描述信息#自定义一个属性name: zhangsan

4、编写启动类

package com.study.springcloud;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.netflix.eureka.EnableEurekaClient;@SpringBootApplication@EnableEurekaClientpublic class ConfigClientApplication_3355 {    public static void main(String[] args) {
        SpringApplication.run(ConfigClientApplication_3355.class,args);
    }
}

5、编写conroller测试

package com.study.springcloud.controller;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Value;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class DemoController {    private static final Logger log = LoggerFactory.getLogger(DemoController.class);    @Value("${name}")
    private String name;    @RequestMapping("/demo")
    public String demo(){
        log.info("demo ok!!!");        return "demo ok,name:"+name;
    }
}

访问 http://localhost:3355/demo
image

在项目中,配置里面的属性(如name属性)可能会根据环境(开发环境,测试环境)不同,值也是不一样的。所以我们在springboot中可以配置多套环境

1、新建开发环境application-dev.yaml

name: zhangsan-dev

2、新建测试环境application-test.yaml

name: lisi-test

3、在修改主配置文件application.yaml
image
4、重新访问 http://localhost:3355/demo
image

把配置文件上传到远端仓库

6、在Gitee上新建文件

image
application.yaml配置文件
image
application-dev.yaml配置文件
image
application-test.yaml配置文件
image
3个文件
image

7、删除项目中的所有yaml配置文件

8、启动config服务springcloud-config-client-3344

9、访问localhost:3344/configclient-dev.yaml 获取配置环境,缓存到本地

image
查看控制台输出缓存的地址
image

10、在config客户端=springcloud-config-client-3355创建bootstrap.yaml配置文件

#config server地址spring:
  cloud:
    config:
      discovery:
        #根据集群注册中心服务器id获取config sever,不要写死,建议在集群获取
        service-id: SPRINGCLOUD-CONFIG-SERVER
        #开启当前configclient 根据服务id去注册中心获取
        enabled: true
        #获取配置文件 1、分支 2、文件名 3、环境
      label: master
      name: configclient
      profile: dev#配置注册中心#Eureka配置,服务注册到哪里eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: springcloud-cofig-client-3355  #修改Eureka默认描述信息

11、启动测试

1、启动eureka集群springcloud-eureka-7001
2、启动config服务端springcloud-config-server-3344
3、启动config客户端springcloud-config-client-3355
image
4、更改bootstrap.yaml配置,重启3355
image
image

注意

config客户端配置如果使用application.yaml命名,会访问远程连接 http://localhost:8888 ,
application.yaml命名是用于已开发完成的项目

Config手动配置刷新

当远程git仓库中配置发生变化时,不需要重启微服务就可以直接读取远端修改之后的配置信息,这种就叫做手动配置刷新

1、在controller中添加@RefreshScope注解

image

2、在bootstrap.yaml配置文件中添加 端点暴露,重启。

image

3、修改远程配置文件

image

4、打开控制台输入curl -X POST http://localhost:3355/actuator/refresh

image
image

配置完之后以后每次在远端修改配置文件只需要走第4步就可以了


路由网关组件:Gateway


Gateway组件简介

Gateway提供了一个在springmvc之上构建API网关的库。springcloudgateway旨在提供一种简单而有效的方法来路由到api,并为api提供横切关注点,比如:安全性、监控/度量和弹性。

1.特性

  • 基于springboot2.x 和 spring webFlux 和 Reactor 构建 响应式异步非阻塞IO模型

  • 动态路由

  • 请求过滤

网关 gateway = 断言predicate + 过滤(后置filler)

  • 断言:当请求到达网关时,网关前置处理

  • 过滤:当请求满足断言的所有条件之后,会向后端服务转发,在向后端服务转发之前会经过一些过滤

Gateway组件使用

1、新建一个子模块springcloud-Gateway-7979

image

2、导入相关依赖

 <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--引入Gateway网关依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
    </dependencies>

3、编写主启动类

package com.study.springcloud;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class GatewayApplication_7979 {    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication_7979.class,args);
    }
}

4、编写application.yaml配置文件

server:
  port: 7979spring:
  application:
    name: springcloud-Gateway-7979
  #Gateway配置
  cloud:
    gateway:
      routes:
        - id: dept8001                # 指定路由唯一标识
          uri: http://localhost:8001/ # 指定路由服务的地址
          predicates:
            # 指定路由规则,及访问当前端口localhost:7979/dept/get/的时候会转发到localhost:8001/dept/get/下所有路径
            - Path=/dept/get/**

        - id: dept8002                # 指定路由唯一标识
          uri: http://localhost:8002/ # 指定路由服务的地址
          predicates:
            # 指定路由规则,及访问当前端口localhost:7979/dept/list的时候会转发到localhost:8002/dept/list
            - Path=/dept/listeureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: Gateway7979.com
    prefer-ip-address: true

5、启动测试

1、启动eureka注册中心集群springcloud-eureka-7001
2、启动服务提供者springcloud-provider-dept-8001springcloud-provider-dept-8002
3、启动Gateway路由网关springcloud-Gateway-7979
image

image

配置路由服务负载均衡

1、编写application.yaml

image

路由predicate(断言,验证)

网关 gateway = 断言predicate + 过滤(后置filler)

  • 断言:当请求到达网关时,网关前置处理

  • 过滤:当请求满足断言的所有条件之后,会向后端服务转发,在向后端服务转发之前会经过一些过滤

image

路由Filter以及自定义filter

一、使用内置的Filter

image

二、自定义全局Filter

自定义全局filter:所有请求都要经过全局filter之后再转发到后端服务

新建一个全局配置类实现GlobalFilter, Ordered接口

package com.study.springcloud.filters;import org.springframework.cloud.gateway.filter.GatewayFilterChain;import org.springframework.cloud.gateway.filter.GlobalFilter;import org.springframework.context.annotation.Configuration;import org.springframework.core.Ordered;import org.springframework.http.server.reactive.ServerHttpRequest;import org.springframework.http.server.reactive.ServerHttpResponse;import org.springframework.web.server.ServerWebExchange;import reactor.core.publisher.Mono;/**
 * 自定义网关全局filter
 */@Configurationpublic class CustomerGlobalFilter  implements GlobalFilter, Ordered {    //类似javaweb doFilter
    //exchange : 交换   request response   封装了 request response
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {        //httprequest对象
        ServerHttpRequest request = exchange.getRequest();        //httpresponse对象
        ServerHttpResponse response = exchange.getResponse();
        System.out.println("经过全局Filter处理.......");
        Mono<Void> filter = chain.filter(exchange);//放心filter继续向后执行
        System.out.println("响应回来Filter处理......");        return filter;
    }    //order 排序  int数字:当又多个filter的时候,用来指定filter执行顺序  默认顺序按照自然数字进行排序 , -1 在所有filter执行之前执行
    @Override
    public int getOrder() {        return -1;
    }
}

通过网关提供web路径查看路由详细规则

1、applicaiton.yaml添加以下配置

management:
  endpoints:
    web:
      exposure:
        include: "*"

2、访问http://localhost:7979/actuator/gateway/routes 路径

image