手动搭建微服务项目(springcloud+springboot+mybatis)

一、创建普通maven项目,该项目为微服务架构中的父项目

父项目:springcloud pom.xml


<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.0modelVersion>

    <groupId>cn.cduestcgroupId>
    <artifactId>springcloudartifactId>
    <version>1.0-SNAPSHOTversion>
    
    
    <packaging>pompackaging>

    <properties>
        <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
        <maven.compiler.source>1.8maven.compiler.source>
        <maven.compiler.target>1.8maven.compiler.target>
        <junit.version>4.12junit.version>
        <lombok.version>1.18.10lombok.version>
        <log4j.version>1.2.12log4j.version>
    properties>

    <dependencyManagement>
        <dependencies>
            
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-dependenciesartifactId>
                <version>Greenwich.SR1version>
                <type>pomtype>
                <scope>importscope>
            dependency>

            
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-dependenciesartifactId>
                <version>2.1.4.RELEASEversion>
                <type>pomtype>
                <scope>importscope>
            dependency>

            
            <dependency>
                <groupId>mysqlgroupId>
                <artifactId>mysql-connector-javaartifactId>
                <version>5.1.46version>
            dependency>

            
            <dependency>
                <groupId>com.alibabagroupId>
                <artifactId>druidartifactId>
                <version>1.1.12version>
            dependency>

            
            <dependency>
                <groupId>org.mybatis.spring.bootgroupId>
                <artifactId>mybatis-spring-boot-starterartifactId>
                <version>1.1.1version>
            dependency>

            
            <dependency>
                <groupId>log4jgroupId>
                <artifactId>log4jartifactId>
                <version>${log4j.version}version>
            dependency>

            
            <dependency>
                <groupId>ch.qos.logbackgroupId>
                <artifactId>logback-coreartifactId>
                <version>1.2.3version>
            dependency>

            
            <dependency>
                <groupId>junitgroupId>
                <artifactId>junitartifactId>
                <version>${junit.version}version>
            dependency>

            
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
                <version>${lombok.version}version>
            dependency>
            
        dependencies>
    dependencyManagement>
project>

二、创建第一个子项目模块

1、springcloud-api pom.xml


<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>springcloudartifactId>
        <groupId>cn.cduestcgroupId>
        <version>1.0-SNAPSHOTversion>
    parent>
    <modelVersion>4.0.0modelVersion>

    <groupId>cn.cduestc.springcloudgroupId>
    <artifactId>springcloud-apiartifactId>

    
    <dependencies>
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
        dependency>
    dependencies>
project>

2、在该模块中编写实体类

package cn.cduestc.springcloud.pojo;

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

import java.io.Serializable;

@Data
@NoArgsConstructor
@Accessors(chain = true)  //开启该类的链式写法
//实体类必须实现Serializable接口,保证在微服务架构项目模块之间进行通信时可以序列化
public class Dept implements Serializable{

    private Long id;
    private String name;
    //微服务架构一个服务对应一个数据库,不同信息可能存在不同数据库,该字段表示存在哪个数据库
    private String db_source;
}

三、创建第二个子项目模块(服务提供者)

1、springcloud-provider-dept-8081 pom.xml

        
        <dependency>
            <groupId>cn.cduestc.springcloudgroupId>
            <artifactId>springcloud-apiartifactId>
            <version>1.0-SNAPSHOTversion>
        dependency>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-eurekaartifactId>
            <version>1.4.6.RELEASEversion>
        dependency>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-actuatorartifactId>
        dependency>
        
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
        dependency>
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
        dependency>
        
        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>druidartifactId>
        dependency>
        
        <dependency>
            <groupId>ch.qos.logbackgroupId>
            <artifactId>logback-coreartifactId>
        dependency>
        
        <dependency>
            <groupId>log4jgroupId>
            <artifactId>log4jartifactId>
        dependency>
        
        <dependency>
            <groupId>org.mybatis.spring.bootgroupId>
            <artifactId>mybatis-spring-boot-starterartifactId>
        dependency>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-testartifactId>
        dependency>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        
        
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-devtoolsartifactId>
        dependency>

2、在resources下创建mybatis/mybatis-config.xml

在该文件下配置mybatis框架的相关配置



<configuration>
    
    <settings>
        <setting name="cacheEnabled" value="true"/>
    settings>
configuration>

3、在resources下创建mybatis/mapper/DeptMapper.xml



<mapper namespace="cn.cduestc.springcloud.mapper.DeptMapper">

    <insert id="addDept" parameterType="Dept">
        INSERT INTO db01.dept(name,db_source) VALUES (#{name},DATABASE())
    insert>

    <select id="selectById" parameterType="Long" resultType="Dept">
        SELECT * FROM db01.dept WHERE id=#{id}
    select>

    <select id="selectAll" resultType="Dept">
        SELECT * FROM db01.dept
    select>

mapper>

4、在resources下创建application.yml

server:
  port: 8081

#mybatis相关配置
mybatis:
  #配置实体类的包
  type-aliases-package: cn.cduestc.springcloud.pojo
  #配置mybatis配置文件的路径
  config-location: classpath:mybatis/mybatis-config.xml
  #配置mybatis的mapper文件的位置
  mapper-locations: classpath:mybatis/mapper/*.xml

#spring相关配置
spring:
  #给该模块取个名字
  application:
  	name: springcloud-provider-dept
  datasource:
    #更换连接数据库的数据源
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: org.gjt.mm.mysql.Driver
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8

5、在该模块主包下创建启动类

package cn.cduestc.springcloud;

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

@SpringBootApplication
@EnableEurekaClient    //配置后该类为eureka客户端启动类
@EnableDiscoveryClient   //配置后可以发现服务的信息
public class DeptProvider {
    public static void main(String[] args) {
        SpringApplication.run(DeptProvider.class,args);
    }
}

6、在该模块下编写mapper层、service层、controller层

controller层代码

package cn.cduestc.springcloud.controller;

import cn.cduestc.springcloud.pojo.Dept;
import cn.cduestc.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;

@RestController
public class DeptController {

    @Autowired
    private DeptService deptService;

    @PostMapping("/dept/add")
    public boolean addDept(Dept dept){
        return deptService.addDept(dept);
    }

    @GetMapping("/dept/select/{id}")
    public Dept selectOne(@PathVariable("id") Long id){
        return deptService.selectById(id);
    }


    @GetMapping("/dept/selectAll")
    public List<Dept> selectAll(){
        return deptService.selectAll();
    }
}

四、创建第三个子项目模块(服务消费者)

1、springcloud-consumer-80 pom.xml


<dependency>
    <groupId>org.springframework.cloudgroupId>
    <artifactId>spring-cloud-starter-ribbonartifactId>
    <version>1.4.6.RELEASEversion>
dependency>

<dependency>
    <groupId>org.springframework.cloudgroupId>
    <artifactId>spring-cloud-starter-eurekaartifactId>
    <version>1.4.6.RELEASEversion>
dependency>
<dependency>
    <groupId>cn.cduestc.springcloudgroupId>
    <artifactId>springcloud-apiartifactId>
    <version>1.0-SNAPSHOTversion>
dependency>
<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-devtoolsartifactId>
dependency>

2、创建一个配置类,将restTemplate的bean注册到容器中

①RestTemplate提供了常见的Rest请求方案的模板,提供了多种便捷访问远程http服务的方法(RestTemplate是一个模板类,该类提供了多种远程访问http服务的方式,比如:get、post、put、delete…)

②RestTemplate提供的访问远程http服务的方法格式:getForObject(String url, Class< T > responseType, Object… uriVariables)

url:表示请求远程http的地址
responseType:表示响应返回值的类型的字节码对象
uriVariables:表示远程访问传递的参数,该参数可以没有,可以封装在对象中,也可是封装在map中
package cn.cduestc.springcloud.config;

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

@Configuration   //加上该注解,将该类标记为配置类,可以在该类中配置springboot的相关配置
public class ConfigBean {

    @Bean    //将该方法返回的bean注册到容器中
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }

}

3、创建该项目的controller层,用于远程调用服务提供者的服务

package cn.cduestc.springcloud.controller;

import cn.cduestc.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 DeptController {

    /**
     *  分析:消费者不能有service层,所以使用restTemplate进行远程调用,需要将restTemplate的bean注册到容器中
     */
    @Autowired
    private RestTemplate restTemplate;

    //当进行远程调用时,url的前缀是固定的,所有我们可以设置一个常量
    private static final String REST_URL_PREFIX = "http://localhost:8081";

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

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

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

}

4、配置一个启动类(服务消费者的启动类)

5、启动服务提供者和服务消费者的启动类,当我们访问服务消费者的接口时,可以通过远程访问到服务提供者的接口,实现了微服务不同服务模块之间的通信(单向)

6、使用springcloud进行通信和dubbo+zookeeper的RPC通信的区别?

①本质区别:springcloud的通信机制是基于http的restful api,而dubbo是基于RPC的远程过程调用

②代码区别:

springcloud是服务消费者在controller中使用RestTemplate进行基于http的远程调用。
dubbo是使用注册中心,在不同模块的yml配置文件中配置相同注册中心地址,服务提供者将服务放入注册中心,在添加@Reference注解后,服务消费者会在服务中心去获取该服务接口,从而达到不同模块之间的调用

五、创建第四个子项目模块(Eureka服务端)

Eureka是用来做注册中心的,类似于zookeeper。服务提供者将自己的服务放到注册中心,服务消费者需要时就去拿,这样就解决了上面单纯使用RestTemplate进行远程调用的的弊端。

1、springcloud-eureka-7001 pom.xml


        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-eureka-serverartifactId>
            <version>1.4.6.RELEASEversion>
        dependency>

2、配置application.yml

server:
  port: 7001

#Eureka配置
eureka:
  instance:
    hostname: localhost   #Eureka服务端的实例名称
  client:
    register-with-eureka: false    #表示是否向eureka注册中心注册自己
    fetch-registry: false    #fetch-registry为false时,表示自己为注册中心
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/    #注册中心的地址

3、在该子模块的启动类上加上一个注解

@EnableEurekaServer     //配置该注解,表示该启动类是eureka的服务端启动类,可以接收其他服务注册进来

4、在服务提供者导入Eureka的的客户端依赖(将该模块的服务注册进注册中心)


<dependency>
    <groupId>org.springframework.cloudgroupId>
    <artifactId>spring-cloud-starter-eurekaartifactId>
    <version>1.4.6.RELEASEversion>
dependency>

5、在Eureka的客户端的application.yml中配置Eureka的相关配置(配置完之后,在Eureka界面就可以看到该服务了)

eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/    #配置注册中心地址
  instance:
    instance-id: springcloud-provider-dept8001    #配置服务名称

6、如果想要监控Eureka的服务信息

①导入一个依赖

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-actuatorartifactId>
dependency>
②在application.yml中配置服务的信息
info:
  app.name: springcloud-zhanghu
  company.name: cduestc

7、服务发现

①在服务提供者controller里面添加代码
DiscoveryClient 是一个接口,在其实现类中存储了服务对应的一些信息,当我们访问这个controller路径时,可以输出服务相关的信息,实现了服务发现
//该接口用于发现服务,其实现类中存储了服务的一些信息
@Autowired
private DiscoveryClient discoveryClient;
//输出eureka的服务发现信息(用来获取注册进来的服务的一些信息)
@GetMapping("/dept/discovery")
public Object discovery(){
    //获取哪些服务已经注册
    List<String> services = discoveryClient.getServices();
    System.out.println("discovery=>service=>"+services);
    //根据某个服务名获取该服务的实例
    List<ServiceInstance> instances = discoveryClient.getInstances("SPRINGCLOUD-PROVIDER-DEPT");
    for (ServiceInstance instance : instances) {
        System.out.println(
                instance.getHost()+"\t"+
                instance.getPort()+"\t"+
                instance.getUri()+"\t"+
                instance.getServiceId()+"\t"
        );
    }
    return this.discoveryClient;
}
②在启动类上加添加注解
@EnableDiscoveryClient   //服务的发现

8、Eureka集群

①创建多个和springcloud-eureka-7001一样的子模块
②修改application.yml
eureka:
	client:
		service-url:
			# 单体:defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/    #注册中心的地址
			defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/  # 集群

面试题

CAP原则是什么?

答:
C(Consistency)强一致性 :在分布式系统中的所有数据备份,在同一时刻是同样的值。(等同于所有节点访问同一份最新的数据副本)
A(Availability)可用性 :在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
P(Partition tolerance)分区容错性:以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。

BASE原则

答:
Base原则是CAP原则的延伸,提出了三个主要的概念。
基本可用性:当分布式系统出现故障时,允许损失部分服务可用性,但是项目最核心的服务必须要能正常运行,淘宝双十一时,为了应对用户量的激增,部分顾客会被引导进入降级页面,服务层也只提供降级服务,这也就是损失部分可用性的体现。
软状态:软状态是指系统允许存在中间状态,而该中间状态不会影响系统的可用性。(典型的例子如在分布式文件系统中,数据的写入往往是先写入一份,再异步生成多个副本)。
最终一致性:指系统中的副本数据经过一定时间过后,最终能达到一致性。

作为服务注册中心,Eureka对比zookeeper的优势?

答:
著名的CAP理论指出,一个系统不能同时满足C、A、P,由于分布区容错性P在分布式系统中是必须要保证的,因此我们需要在C、A、之中进行权衡。
Zookeeper保证的是CP,Eureka保证的是AP。
Zookeeper:当向注册中心查询服务列表时,我们可以接受注册中心返回的数据不是实时的,但不能接受服务直接down掉。所以就是说,服务注册中心对可用性的要求高于一致性。在Zookeeper中出现这种情况,当master节点因为网络故障和其他节点失去联系,剩余节点会重新选举leader。问题在于,选举时间一般在30~120s,且选举期间Zookeeper是不可用的,直接导致了选举期间服务中心的瘫痪。在云部署环境下,因为网络问题使Zookeeper集群失去master节点的概率很大,虽然最后能恢复,但漫长的选举时间导致注册长期不可用是不能容忍的。
Eureka:Eureka在设计的时候就首先保证的是可用性。Eureka各个节点都是平等的,几个节点挂掉不会影响其它节点的正常工作,剩余的节点依然可以提供注册和查询服务。Eureka的客户端向某个Eureka注册时,如果发现连接失败,则会自动切换至其他节点,只要有一台Eureka在,就能保证注册服务的可用性,只不过查到的数据可能不是最新的。除此之外,Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:
①Eureka不再从注册列表中移除因为长时间没有收到心跳而应该过期的服务
②Eureka仍然能够接受新服务的注册和查询要求,但不会被同步到其他节点上(即保证当前节点的可用性)
③当网络稳定时,当前实例新注册的信息会被同步到其他节点上
因此,Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像Zookeeper那样使整个注册服务瘫痪。

六、模拟多服务节点,做Ribbon负载均衡

1、创建多个服务提供者模块,里面除了application.yml中一些本模块特别的配置,其他均一致。每个模块连接不同的数据库。

2、此时多个服务已经注册进去,但是我们服务消费者调用时还是调用的8081端口号的服务,所以我们需要将controller中的RestTemplate的地址前缀修改为一个变量,可以表示所有子模块的变量。

/**这里不应该使用"http://localhost:8081",因为这里写死了,直接去访问8081端口下的服务,而我们使用
     * Eureka做了注册中心,且做了注册中心集群,使用了Ribbon做负载均衡,所以不应该将服务地址写死,这里的
     * 服务地址应该是一个变量
     */
    //private static final String REST_URL_PREFIX = "http://localhost:8081";
    private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";

3、给服务消费者导入依赖

springcloud-consumer-80 pom.xml


        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-ribbonartifactId>
            <version>1.4.6.RELEASEversion>
        dependency>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-eurekaartifactId>
            <version>1.4.6.RELEASEversion>
        dependency>

4、在服务消费者的配置文件中写Eureka相关配置

server:
  port: 80

#Eureka相关配置
eureka:
  client:
    register-with-eureka: false  #配置为false之后,不会向服务中心注册该服务
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

5、在返回RestTemplate的配置类中,返回RestTemplate的方法上加注解

@LoadBalanced   //因为做远程调用的是RestTemplate,所以负载均衡也应该在RestTemplate上面做,所以在注册Bean时添加@LoadBalanced

6、在服务消费者的启动类上加上注解,设置该服务为Eureka客户端

@EnableEurekaClient   //配置为Eureka客户端启动类

7、最后启动所有Eureka注册中心,所有服务提供者节点,服务消费者,即可模拟实现负载均衡效果。(每次服务消费者进行数据访问,都是访问的不同的节点,不同的数据库)

8、怎么自定义配置负载均衡算法?

①在服务消费者的启动类的上级包目录下,自定义负载均衡算法类
②将自定义的算法类使用@Bean注解注入到容器中
③在启动类上加注解@RibbonClient,配置name,configuration参数

9、Feign负载均衡

feign是声明式的web service客户端,它让微服务之间的调用变得更简单,类似controller调用service。springcloud集成了Ribbon和Eureka,可在使用Feign时提供负载均衡的http客户端。

Feign的作用?

和Ribbon一样,是用来做负载均衡的。不同于Ribbon,实现Feign只需要创建一个接口,并使用注解的方式来配置它(类似于之前的Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可)。
Feign和Ribbon的区别?
Feign是使用接口加配置的方式实现负载均衡,相对来说更加符合面向接口编程的思想;Ribbon使用RestTemplate来实现远程调用和负载均衡,相对来说更加符合Restful风格;所以说各有各的特点。

七、怎么配置Hystrix的服务熔断机制(针对服务提供者,服务端)

1、创建一个springcloud-provider-dept-hystrix-8081子模块,导入依赖


<dependency>
   <groupId>org.springframework.cloudgroupId>
   <artifactId>spring-cloud-starter-hystrixartifactId>
   <version>1.4.6.RELEASEversion>
dependency>

2、在controller类中添加每个服务的备用服务

核心是在原来的方法上加上@HystrixCommand(fallbackMethod = “hystrixSelectOne”),回调的方法就是备用方法

package cn.cduestc.springcloud.controller;

import cn.cduestc.springcloud.pojo.Dept;
import cn.cduestc.springcloud.service.DeptService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
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.RestController;

@RestController
public class DeptController {
   	@Autowired
    private DeptService deptService;

    //获取单个数据
    @GetMapping("/dept/select/{id}")
    @HystrixCommand(fallbackMethod = "hystrixSelectOne")  //添加该注解后,表示对该服务添加了hystrix熔断机制,在该服务挂掉时,会调用备用服务
    public Dept selectOne(@PathVariable("id") Long id){
        Dept dept = deptService.selectById(id);
        //判断如果输入错误id,没有查询到数据,那么抛出一个运行时异常
        if (dept == null){
            throw new RuntimeException("您输入的id没有对应的值哦!!!");
        }
        return dept;
    }
    //该方法是在服务挂掉后,启用hystrix熔断机制调用的备用方法
    public Dept hystrixSelectOne(@PathVariable("id") Long id){
        return new Dept()
                .setId(id)
                .setName("对不起,"+id+"没有对应的数据")
                .setDb_source("没有对应的信息,当然没有数据库哦");
    }

}

3、在启动类上加注解

注意:不是@EnableHystrix注解

@EnableCircuitBreaker    //开启hystrix熔断器

八、服务降级机制(针对服务消费者,客户端;需要在使用了Feign的前提下进行)

1、在客户端上写一个类实现FallbackFactory接口,覆写方法,将该类注册到容器中@Component。

2、返回需要进行服务降低的服务接口,即返回service层类型的Bean。

3、在service层的接口中添加注解:@FeignClient(value=“进行Feign的服务名”,fallbackFactory=进行了服务降级的类的Class对象)

4、进行服务降级后的效果:如果该服务突然熔断或关闭,是不会直接返回无响应,而是返回我们自定义配置的服务降级后的提示信息。

问题:服务熔断和服务降级的使用场景及的区别?

服务熔断:服务熔断是在当服务端某个服务突然挂掉,服务端对这种情况作出的一种应对策略;服务端会为服务添加一个备用服务,当原本的服务挂掉,不至于因为这一个环节的服务挂掉而导致所有的服务都出现异常。

服务熔断是部署在服务端的,当某个服务异常或者超时,引起的一种应对策略。

服务降级:当某一个时间段,部署的许多服务中,某一些服务访问量相当大,而个别服务几乎没有访问,那么,就需要对没有访问的服务进行服务降级操作。将这些服务关闭,当客户端访问时,返回一些提示服务降级关闭的信息。

服务降级是部署在客户端的,服务熔断或超时时,服务将不再被调用,并返回一些默认的信息。整体服务水平下降了。

九、使用Dashboard对Hystrix进行监控

1、创建一个监控模块(和服务消费者模块差不多),导入依赖

<dependencies>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-hystrix-dashboardartifactId>
            <version>1.4.6.RELEASEversion>
        dependency>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-hystrixartifactId>
            <version>1.4.6.RELEASEversion>
        dependency>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-ribbonartifactId>
            <version>1.4.6.RELEASEversion>
        dependency>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-eurekaartifactId>
            <version>1.4.6.RELEASEversion>
        dependency>
        <dependency>
            <groupId>cn.cduestc.springcloudgroupId>
            <artifactId>springcloud-apiartifactId>
            <version>1.0-SNAPSHOTversion>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-devtoolsartifactId>
        dependency>
    dependencies>

2、创建启动类,并添加注解

@EnableHystrixDashboard    //开启Hystrix的Dashboard监控

3、在需要监控的服务提供者模块的启动类中添加代码

注意:此时的服务提供者需要是进行了熔断处理的服务,因为Dashboard监控是建立在Hystrix基础上

(注册一个servlet对hystrix进行流监控,固定代码)

//注册一个servlet,对hystrix进行流监控   固定代码
    @Bean
    public ServletRegistrationBean hystrixMetricsStreamServlet(){
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
        servletRegistrationBean.addUrlMappings("/actuator/hystrix.stream");
        return servletRegistrationBean;
    }

4、在启动类上加注解(开启熔断器,才能进行监控)

@EnableCircuitBreaker  //开启hystrix熔断器

十、进行Zuul路由配置

1、创建一个子模块,用于做zuul配置。 springcloud-zuul-9527 pom.xml

<dependencies>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-zuulartifactId>
            <version>1.4.6.RELEASEversion>
        dependency>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-hystrix-dashboardartifactId>
            <version>1.4.6.RELEASEversion>
        dependency>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-hystrixartifactId>
            <version>1.4.6.RELEASEversion>
        dependency>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-ribbonartifactId>
            <version>1.4.6.RELEASEversion>
        dependency>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-eurekaartifactId>
            <version>1.4.6.RELEASEversion>
        dependency>
        <dependency>
            <groupId>cn.cduestc.springcloudgroupId>
            <artifactId>springcloud-apiartifactId>
            <version>1.0-SNAPSHOTversion>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-devtoolsartifactId>
        dependency>
    dependencies>

2、配置zuul的application.yml

server:
  port: 9527

#给zuul取个名字
spring:
  application:
    name: springcloud-zuul

#Eureka配置
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/     #配置注册中心地址
  instance:
    instance-id: zuul9527.com  #zuul状态显示名称
    prefer-ip-address: true  #显示ip

#zuul配置
zuul:
  routes:
    mydept: {serviceId: springcloud-provider-dept,path: /mydept/**}   #配置map集合,用于确定路由的统一访问路径
#    mydept.serviceId: springcloud-provider-dept
#    mydept.path: /mydept/**
  ignored-services: "*"   #表示要忽略的访问路径,因为我们配置了新的访问路径,需要将原来的路径禁止;配通配符隐藏全部
  prefix: /hu    #给所有的访问添加统一的访问前缀

#点进服务展示相关信息
info:
  app.name: springcloud-zhanghu
  company.name: cduestc

3、在启动类上加注解(开启路由的代理)

@EnableZuulProxy   //开启路由代理

十一、Feign

1、导入依赖

<dependency>
 	<groupId>org.springframework.cloudgroupId>
 	<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>

二、编写一个Feign的接口

①添加注解@FeignClient(value = “springcloud-provider-dept”),其中value的值必须是需要调用的服务的名称

②编写需要调用的方法,并且配置调用方式及路径

package cn.cduestc.springcloud.config;

import org.springframework.cloud.openfeign.FeignClient;
import cn.cduestc.springcloud.pojo.Dept;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.List;

@FeignClient(value = "springcloud-provider-dept")
public interface FeignConfit {
    @GetMapping("/dept/selectAll")
    List<Dept> selectAll3();

}

3、在启动类上加上注解@EnableFeignClients开启Feign客户端使用。

4、将Feign接口注入到controller中,直接进行方法调用即可,即实现了不同服务之间的调用,且负载均衡。

	@Autowired
    private FeignConfit FeignConfit;
    @GetMapping("/consumer/dept/selectAll4")
    public List<Dept> selectAll2(){
        return FeignConfit.selectAll3();
    }

你可能感兴趣的:(手动搭建微服务项目(springcloud+springboot+mybatis))