SpringCloud入门

前言

目前Springboot是新一代的JavaEE开发标准,目前很多企业都在送Spring转型向SpringBoot进行开发,这样带来了一个问题,随着体系越来越大,用户越来越多,一个SpringBoot项目不能承载所有的服务,因此需要多个SpringBoot项目来分别负责多个业务,简单来说,就是模块化

微服务的4个核心问题

  1. 服务很多,客户端该怎么访问
  2. 服务很多,服务之间如何通信
  3. 服务如何治理
  4. 服务宕机了怎么办

解决方案:

	SpringCloud

SpringCloud是一个生态!

  • Spring Cloud NetFlix(停止维护):一站式解决方案
    访问:api网关,zuul组件
    通信:Feign,基于Http通信方式,同步,阻塞
    服务注册发现:Eureka
    熔断机制:Hystrix,使得单个服务出现故障时,整个集群可用性不受到影响
  • Apache Dubbo Zookeeper:半自动,需要整合别人的东西
    访问:没有,使用第三方组件,或者自己实现
    通信:Dubbo,高性能
    服务注册发现:Zookeeper
    熔断机制:借助于Hystrix

Dubbo这个方案并不完善

  • Spring Cloud Alibaba:最新的一站式解决方案
    更加简单

新概念:服务网格(Server Mesh)——下一代的微服务标准

什么是微服务

微服务强调的是服务的大小,这个服务该去处理什么。是具体解决某一个问题的服务应用

什么是微服务架构

一种新的架构形式,微服务≠微服务架构,别弄混了,这种架构是由Martin Fowler在2014年提出的。

微服务架构是一种架构模式它提倡将单一的应用程序划分成一组小的服务,服务之间相互协调、互相配置,每个服务都有具体的业务,独立部署到生产环境中,可以不同语言,也可以不同数据存储。

简单来说:解耦

微服务优缺点

优点

  1. 每个服务足够内聚、足够小,代码容易理解,这样才能聚集一个指定的业务或业务需求
  2. 开发简单,开发效率高,一个服务只干一件事情
  3. 可以独立开发
  4. 松耦合,在开发或者部署都是独立的
  5. 可以使用不同语言进行开发
  6. 易于于第三方集成,微服务允许容易且灵活的方式集成自动部署,通过持续集成工具,如Jenkins,Hudson,bamboo
  7. 微服务易于维护
  8. 允许融合最新技术
  9. 微服务只是业务逻辑的代码,不会和HTML、CSS或其他界面混合
    10.每个微服务都有自己的存储能力,可以有自己的数据库,也可以有统一的数据库

缺点

  • 开发人员要处理分布式系统的复杂性
  • 多服务运维难度随着服务的增加,压力也在增大
  • 系统部署依赖
  • 服务间通信成本增加
  • 数据一致性可能有问题
  • 系统集成测试
  • 性能监控

微服务技术栈

在这里插入图片描述

为什么使用SpringCloud作为微服务架构

1、选型依据

  • 整体解决方案和框架成熟度
  • 社区热度
  • 可维护性
  • 学习曲线

2、IT公司使用的微服务架构有哪些

  • 阿里:Dubbo+HFS
  • 京东:JSF
  • 新浪:Motan
  • 当当网:DubboX

什么是SpringCloud

在这里插入图片描述
SpringCloud,基于SpringBoot提供的一套微服务解决方案,包括配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等,最终给开发者留出一套简单易懂,易于部署和易于维护的分布式系统开发工具包

它是将服务框架组合起来,通过SpringBoot风格进行再次封装,屏蔽了复杂的配置和实现原理。

SpringCloud和SpringBoot关系

  • SpringBoot用于构建微服务,而SpringCloud用于协调微服务
  • SpringBoot专注于快速方便的开发单个个体微服务
  • SpringCloud将SpringBoot开发的一个个单体微服务整合并管理起来,为各个微服务之间提供:配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等集成服务
  • SpringBoot可以离开SpringCloud独立使用,但是SpringCloud只能依赖于SpringBoot
  • SpringBoot专注于快速、方便的开发单个个体微服务,SpringCloud关注全局的服务治理框架

SpringCloud版本选择

在这里插入图片描述
一般选择最新的稳定版即可。

创建SpringCloud项目

建立一个Maven项目(父工程)

我们在IDEA中建立一个普通的Maven项目,并把它作为一个父工程,删除src目录
在这里插入图片描述

导入依赖

 <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <junit.version>4.12</junit.version>
        <lombok.version>1.8.22</lombok.version>
    </properties>

    <!--打包方式 pom-->
    <packaging>pom</packaging>

    <dependencyManagement>
        <dependencies>
            <!--springCloud的依赖-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>2020.0.2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--springboot的依赖-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.6.6</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--数据库-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.47</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.10</version>
            </dependency>
            <!--springboot启动器-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.2.2</version>
            </dependency>
            <!--junit-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</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>1.2.17</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

这里的dependencyManagement说明父项目只负责依赖的管理,并没有给子项目都导入依赖,而是子项目需要什么依赖自己导入即可。

创建子项目

我们在父项目下:

接口服务

新建一个module——springcloud-api,专注于写接口即可
在这里插入图片描述
导入lombok依赖

    <!--当前的module需要的依赖,如果父依赖中已经配置了版本,这里就不需要写了-->
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.18</version>
        </dependency>

实现接口类Dept

package com.cjh.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 Dept(String dname) {
        this.dname = dname;
    }

    /*
    * 链式写法
    Dept dept = new Dept();
    dept.setDeptNo(11).setDname('sss').setDb_source('001');
    * */
}

在这里插入图片描述

提供服务(服务端)

新建一个module——springcloud-provider-dept-8081,专注于提供服务
在这里插入图片描述
导入依赖

<?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.cjh</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

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

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

    <dependencies>
        <!--我们需要拿到我们的实体类,所以需要配置api module-->
        <dependency>
            <groupId>com.cjh</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <!--数据库-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <!--test-->
        <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>
        <!--jetty-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
        <!--热部署工具-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>
</project>

这里我们通过依赖,拿到我们的实体类
Deptmapper

package com.cjh.springcloud.mapper;

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

import java.util.List;

@Mapper
@Repository
public interface DeptMapper {
    public boolean addDept(Dept dept);

    public Dept queryById(Long id);

    public List<Dept> queryAll();
}

DeptController

package com.cjh.springcloud.controller;

import com.cjh.springcloud.pojo.Dept;
import com.cjh.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();
    }
}

DeptService

package com.cjh.springcloud.service;


import com.cjh.springcloud.pojo.Dept;

import java.util.List;

public interface DeptService {
    public boolean addDept(Dept dept);

    public Dept queryById(Long id);

    public List<Dept> queryAll();
}

DeptServiceImpl

package com.cjh.springcloud.service;

import com.cjh.springcloud.mapper.DeptMapper;
import com.cjh.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 DeptMapper deptMapper;
    @Override
    public boolean addDept(Dept dept) {
        return deptMapper.addDept(dept);
    }

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

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

DeptMapper.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.cjh.springcloud.mapper.DeptMapper">

<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>

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核心配置文件-->
<configuration>


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


</configuration>

application.yml

server:
  port: 8081
#mybatis配置
mybatis:
  type-aliases-package: com.cjh.springcloud.pojo
  mapper-location: classpath:mybatis/mapper/*.xml
  config-location: classpath:mybatis/mybatis-config.xml
#spring配置
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&useSSL=false&serverTimezone = GMT
    username: root
    password: 123456

使用服务(用户)

我们建立一个消费者,来使用我们的服务
在这里插入图片描述
ConfigBean

package com.cjh.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();
    }
}

我们需要建立一个配置类,来使用我们的RestTemplate
RestTemplate:提供多种便捷访问远程http服务的方法,简单的restful服务模板
DeptConsumerController

package com.cjh.springcloud.controller;

import com.cjh.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
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 {

    //理解:消费者,不应该有service层
    //RestTemplate
    //(url,实体:Map,Class<T> responseType)
    @Autowired
    private RestTemplate restTemplate; //提供多种便捷访问远程http服务的方法,简单的restful服务模板

    private static final String REST_URL_PREFIX= "http://localhost:8081";


    @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);
    }


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

由于消费者是没有service层的概念的,因此我们需要通过RestTemplate来实现远程访问服务端。
application.yml

server:
  port: 80

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.cjh</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

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

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

    <!--实体类+web-->
    <dependencies>
        <dependency>
            <groupId>com.cjh</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-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-devtools</artifactId>
        </dependency>
    </dependencies>
</project>

总结

我们通过这一个实例,就可以明显的看出,我们在SpringBoot项目中,所有的服务都在一个项目中完成,我们的员工管理系统,实体类、接口类、接口实现类、配置文件、调用类、视图层等等都在一个项目中,但是我们通过SpringCloud,我们把所有的服务都拆成了一个个模块单独的一个服务,这样就便于管理和维护。


版权声明:本文为m0_46983722原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。