SpringCloud:环境搭建

郎家岭伯爵 2022年05月30日 445次浏览

背景

今天开始着手学习SpringCloud的相关内容。

什么是SpringCloud

SpringCloud是分布式微服务架构的一站式解决方案,它提供了一套简单易用的编程模型,使我们能在SpringBoot的基础上轻松地实现微服务系统的构建。

SpringCloud被称为构建分布式微服务系统的“全家桶”,它并不是某一门技术,而是一系列微服务解决方案或框架的有序集合。它将市面上成熟的、经过验证的微服务框架整合起来,并通过SpringBoot的思想进行再封装,屏蔽掉其中复杂的配置和实现原理,最终为开发人员提供了一套简单易懂、易部署和易维护的分布式系统开发工具包。

SpringCloud中包含了spring-cloud-config、spring-cloud-bus等近20个子项目,提供了服务治理、服务网关、智能路由、负载均衡、断路器、监控跟踪、分布式消息队列、配置管理等领域的解决方案。

实现

微服务架构的四个核心问题

  1. 服务很多,客户端该如何访问? API网关
  2. 服务很多,服务之间该如何通信? HTTP,或者RPC
  3. 如何治理服务? 注册与发现
  4. 服务挂了怎么办? 熔断机制

解决方案:

  1. SpringCloud NetFlix,主要由 Eureka、Ribbon、Feign、Hystrix 等组件组成。
  2. Apache Dubbo + Zookeeper
  3. SpringCloud Alibaba,主要由 Nacos、Sentinel、Seata 等组件组成。

创建总项目

版本选择

Spring版本依赖。

注:

  • Spring官方为我们做好了各种版本选择,在建立项目时需要注意按照要求来选择对应的版本,否则会有各种版本冲突。

创建Maven项目

新建Maven项目(可删除src目录):

总项目pom文件

编辑总项目的pom.xml文件,指定各依赖版本,尤其注意SpringCloudSpringBoot的版本兼容问题:

<?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.langjialing</groupId>
    <artifactId>springcloud</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>15</maven.compiler.source>
        <maven.compiler.target>15</maven.compiler.target>
        <junit.verison>4.12</junit.verison>
        <lombok.version>1.16.18</lombok.version>
        <log4j.version>1.2.17</log4j.version>
    </properties>

    <!-- 指定打包方式:pom -->
    <packaging>pom</packaging>

    <dependencyManagement>
        <dependencies>
             <!-- SpringCloud的依赖! -->
            <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>2020.0.1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- SpringBoot的依赖! 此处需要注意SpringCloud与SpringBoot的版本依赖的冲突!-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.4.2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- 连接数据库的依赖!-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.22</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.2.8</version>
            </dependency>
            <!-- SpringBoot的启动器!-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.1.4</version>
            </dependency>
            <!-- junit单元测试  -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.verison}</version>
                <scope>test</scope>
            </dependency>
            <!-- lombok -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>
            <!--  Log4j   -->
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>

        </dependencies>
    </dependencyManagement>
</project>

新建数据库

新建一个MySQL数据库

新建数据表

新建数据表在IDEA中操作:

  1. 在IDEA中连接刚才创建的数据库:

  2. 创建一个数据表:

create table dept
(
	deptno bigint auto_increment,
	dname varchar(60) null,
	db_source varchar(60) null,
	constraint dept_pk
		primary key (deptno)
)
comment '部门表';
  1. 在数据表中插入数据:

创建模块一:springcloud-api

创建Maven模块

在总项目的目录下新建Module:

创建实体类

package com.langjialing.springcloud.pojo;

import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.io.Serializable;

@Data
@NoArgsConstructor
@Accessors(chain = true)    //链式写法
public class Dept implements Serializable { //实例类务必实现序列化!

    private Long deptno;    //主键
    private String dname;
    private String db_source;   //数据存在哪个数据库

    public String getDname() {
        return dname;
    }

    public void setDname(String dname) {
        this.dname = dname;
    }

    public Long getDeptno() {
        return deptno;
    }

    public void setDeptno(Long deptno) {
        this.deptno = deptno;
    }

    public String getDb_source() {
        return db_source;
    }

    public void setDb_source(String db_source) {
        this.db_source = db_source;
    }
}

至此,springcloud-api模块结束。

模块的文件路径

创建模块二:服务提供者

创建Maven模块

在总项目的目录下新建Module:

编辑pom.xml

此模块pom.xml文件的关键在于需要引入刚才创建的springcloud-api

<?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">
    <parent>
        <artifactId>springcloud</artifactId>
        <groupId>com.langjialing</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-provider-dept-8001</artifactId>

    <properties>
        <maven.compiler.source>15</maven.compiler.source>
        <maven.compiler.target>15</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- 需要拿到实体类,因此需要配置api Module。这个类是我们刚才自己写的Module! -->
        <dependency>
            <groupId>com.langjialing</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
    </dependencies>
</project>

编辑application.yaml

resources目录下创建application.yaml文件:

server:
  port: 8001

mybatis:
  type-aliases-package: com.langjialing.springcloud.pojo
  config-location: classpath:mybatis/mybatis-config.xml
  mapper-locations: classpath:mybatis/mapper/*.xml

spring:
  application:
    name: springcloud-provider-dept
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8
    username: root
    password:

编辑mybatis-config.xml

resources目录下创建mapper路径,并在路径中创建mybatis-config.xml文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- 根标签 -->
<configuration>

    <!-- 开启二级缓存 -->
    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>
</configuration>

创建DeptDao

package com.langjialing.springcloud.dao;

import com.langjialing.springcloud.pojo.Dept;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

import java.util.List;

@Mapper
@Repository
public interface DeptDao {

    public boolean addDept(Dept dept);

    public Dept queryById(Long id);

    public List<Dept> queryAll();
}

创建DeptMapper.xml

resources目录下mybatis路径中,继续创建mapper路径,在mapper路径下创建mybatis-config.xml文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 根标签 -->
<mapper namespace="com.langjialing.springcloud.dao.DeptDao">

    <insert id="addDept" parameterType="Dept">
        insert into dept(dname, db_source)
        values (#{dname},DATABASE());
    </insert>

    <select id="queryById" resultType="Dept" parameterType="Long">
        select * from dept where deptno = #{deptno};
    </select>

    <select id="queryAll" resultType="Dept">
        select * from dept;
    </select>
</mapper>

创建service层

创建DeptService接口

package com.langjialing.springcloud.service;

import com.langjialing.springcloud.pojo.Dept;

import java.util.List;

public interface DeptService {

    public boolean addDept(Dept dept);

    public Dept queryById(Long id);

    public List<Dept> queryAll();
}

创建DeptService实现类

package com.langjialing.springcloud.service;

import com.langjialing.springcloud.dao.DeptDao;
import com.langjialing.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class DeptServiceImpl implements DeptService{
    
    @Autowired
    private DeptDao deptDao;
    
    @Override
    public boolean addDept(Dept dept) {
        return deptDao.addDept(dept);
    }

    @Override
    public Dept queryById(Long id) {
        return deptDao.queryById(id);
    }

    @Override
    public List<Dept> queryAll() {
        return deptDao.queryAll();
    }
}

创建controller层

package com.langjialing.springcloud.controller;

import com.langjialing.springcloud.pojo.Dept;
import com.langjialing.springcloud.service.DeptService;
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.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

//提供Restful服务
@RestController
public class DeptController {
    
    @Autowired
    private DeptService deptService;
    
    @PostMapping("/dept/add")
    public boolean addDept(Dept dept){
        return deptService.addDept(dept);
    }
    
    @GetMapping("/dept/get/{id}")
    public Dept get(@PathVariable("id") Long id){
        return deptService.queryById(id);
    }
    
    @GetMapping("/dept/list")
    public List<Dept> queryAll(){
        return deptService.queryAll();
    }
}

创建启动类

package com.langjialing.springcloud;

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

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

测试模块

模块的文件路径

创建模块三:服务消费者

创建Maven模块

编辑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">
    <parent>
        <artifactId>springcloud</artifactId>
        <groupId>com.langjialing</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-consumer-dept-80</artifactId>

    <properties>
        <maven.compiler.source>15</maven.compiler.source>
        <maven.compiler.target>15</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.langjialing</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

</project>

编辑application.yaml

这里仅需要配置一个端口号即可。

server:
  port: 80

注册Bean - RestTemplate

RestTemplate是什么?

package com.langjialing.springcloud.config;

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

@Configuration
public class ConfigBean {
    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

创建消费者的controller

package com.langjialing.springcloud.controller;

import com.langjialing.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController
public class DeptConsumerController {

    @Autowired
    private RestTemplate restTemplate;  // 提供多种便捷访问远程http服务的方法,是一个简单的restful服务模板

    //由于请求地址的前半部分是一致的,所以这里可将前缀提取出来
    private static final String REST_URL_PREFIX = "http://localhost:8001/";

    @RequestMapping("/consumer/dept/get/{id}")
    public Dept get(@PathVariable("id") Long id){
        return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id, Dept.class);
    }

    @RequestMapping("/consumer/dept/add")
    public boolean add(Dept dept){
        return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add", dept, boolean.class);
    }

    @RequestMapping("/consumer/dept/list")
    public List<Dept> list(){
        return restTemplate.getForObject(REST_URL_PREFIX+"/dept/list",List.class);
    }
}

创建启动类

package com.langjialing.springcloud;

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

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

服务消费者调用服务提供者测试

这里注意我们的请求地址localhost/consumer/dept.listlocalhost/consumer/dept/get/1localhost/consumer/dept/add?danme='游戏部'

这与此前单体服务的请求产生了本质区别,是微服务的基本实现。

模块的文件路径

总结

至此,我们已经完成了基本的微服务环境搭建。

后续我们将连载springcloud生态的各个组件,最终实现springcloud的完整生态。