SpringCloud-筑基篇

前言

话语

SpringCloud 快速学习教程

SpringCloud 官网最新版本 Finchley SR2 + SpringBoot 2.0.6

快速学完之后可以看看-另一个文档-SpringCloud-进阶-渡劫篇

叮~~~ 你有一个称号请你查收:

  1. 三天筑基 (springcloud-入门阶段)
  2. 四天渡劫 (springcloud-进阶阶段)
  3. 七天化神 (springcloud-项目实战)

编写人员

隐无为

修订版本

1.0

第一章-项目准备

准备环境

1.JDK 1.8+
2.idea 或eclipse编码工具

所需知识

1.有一定的java代码阅读能力
2.学习过SpringBoot

maven创建父项目

创建项目名为:SpringCloud-demo

创建父项目的好处:以后好更新版本

<?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>SpringCloud-demo</groupId>
    <artifactId>SpringCloud-demo</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
	 <!--模块名-->
    <modules>

    </modules>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR2</spring-cloud.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

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

第二章-注册中心-springcloud-server

创建-springcloud-Eureka-项目

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-server</artifactId>
        <groupId>SpringCloud-demo</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <groupId>springcloud-server</groupId>
    <artifactId>springcloud-Eureka</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

</project>

开启一个服务注册中心

启动一个服务注册中心
启动一个服务注册中心的方式很简单,就是在Spring Boot的入口类上
添加一个@EnableEurekaServer注解,如下:
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerRunApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerRunApplication.class, args);
    }
}

配置application.yml

server:
 #端口
  port: 9000 
eureka:
  instance:
    #服务注册中心实例的主机名
    hostname: localhost
    #ip-address: 固定ip地址
    instance-id: ${spring.cloud.client.ip-address}:${server.port}
    preferIpAddress: true
  server:
    #关闭自我保护机制,防止失效的服务也被一直访问 (开发环境)
    enable-self-preservation: false
    #该配置可以修改检查失效服务的时间,每隔5s检查失效服务,默认该配置是 60s (开发环境)
    eviction-interval-timer-in-ms: 5000
  client:
    #是否向服务注册中心注册自己
    registerWithEureka: false
    #是否检索服务
    fetchRegistry: false
    #服务注册中心的配置内容,指定服务注册中心的位置
    serviceUrl:
      defaultZone: http://localhost:9000/eureka/
	  

测试

在浏览器中输入:http://localhost:9000/就能够看到如下页面:

1

第三章-提供者-springcloud-provider

创建 springcloud-provider-1-项目

<?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-demo</artifactId>
        <groupId>SpringCloud-demo</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>springcloud-provider</groupId>
    <artifactId>springcloud-provider</artifactId>
 
    <dependencies>
        <!-- 服务发现客户端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- spring-boot-web -->
        <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>
    </dependencies>


</project>

配置application.yml

#将服务注册到注册中心
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:9000/eureka/
      #healthcheck:
      #enabled: true  #开启自定义健康检查
  instance:
    #eureka服务器在接收到最后一个心跳之后等待的时间,然后才能从列表中删除此实例 默认90s(开发环境)
    lease-expiration-duration-in-seconds: 10
    #eureka客户端需要向eureka服务器发送心跳的频率 默认30s (开发环境)
    lease-renewal-interval-in-seconds: 1
    # ip地址
    #ip-address: 固定ip地址
    #instance-id: ${spring.cloud.client.ip-address}:${server.port}
    #preferIpAddress: true
#配置服务名称及端口
server:
  port: 9001
spring:
  application:
    name: springcloud-provider
# 自定义属性  app name
kd:
  app:
    name: 提供者-1

创建controller提供服务

@RestController
public class TestController {

    @Value("${server.port}")
    String port;

    @Value("${spring.application.name}")
    String name;
    @Value("${kd.app.name}")
    String appName;

    @RequestMapping("/test")
    public String test() {
        return appName+"上线测试:"+name+":"+port;
    }
}

启动提供者

@SpringBootApplication
@EnableDiscoveryClient  //注册服务到注册中心去
public class ProviderRun_1 {
    public static void main(String[] args) {
        SpringApplication.run(ProviderRun_1.class, args);
    }
}

浏览器查看

http://localhost:9001/test

2

再查看注册中心地址 http://localhost:9000/

发现服务列表有 springcloud-provider

3

显示ip而不是主机的方法

找到 application.yml 以下属性把#去掉就行了

    #instance-id: ${spring.cloud.client.ip-address}:${server.port}
    #preferIpAddress: true

4

注意显示IP和主机的区别?

1.显示主机方式:好处是提供服务用主机名比较直观,但是要添加到hosts里去,
不然不同机器是识别不了服务的。
2.显示ip的方式:以IP地址显示,局域网内访问很方便。
3.推荐方式:组合用,开启preferIpAddress: true 即可

第四章-服务消费者(ribbon方式)

maven创建 spirngcloud-ribbon-client

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-demo</artifactId>
        <groupId>SpringCloud-demo</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>spirngcloud-ribbon-client</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>


        <!--添加Hystrix依赖 断路器容错保护-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <!--监控中心-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>


    </dependencies>
</project>

创建Ribbon启动类

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

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

    @Autowired
    RestTemplate restTemplate;


    @RequestMapping(value = "/test")
    public String test(){
        return restTemplate.getForObject("http://springcloud-provider/test",String.class);
    }

}

配置application.yml

#将服务注册到注册中心
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:9000/eureka/
      #healthcheck:
      #enabled: true  #开启自定义健康检查
  instance:
    #eureka服务器在接收到最后一个心跳之后等待的时间,然后才能从列表中删除此实例 默认90s(开发环境)
    lease-expiration-duration-in-seconds: 10
    #eureka客户端需要向eureka服务器发送心跳的频率 默认30s (开发环境)
    lease-renewal-interval-in-seconds: 1
server:
  port: 9004
#配置服务名称及端口
spring:
  application:
    name: spirngcloud-ribbon-client

浏览器查看结果

http://localhost:9004/test

5

第五章-客户端负载均衡

什么是负载均衡?

负载均衡是我们处理高并发、缓解网络压力和进行服务端扩容的解决方案

负载均衡分为两种

1.服务端负载均衡

Nginx就是服务端负载均衡的例子
由Nginx 分发器统一反向代理请求地址

2.客户端负载均衡

不是统一分发,而是由客户端自己选择,如果你学过dubbo,它就是客户端负载均衡

Ribbo消费者是否支持负载均衡?

可以的,Ribbo的实现本身就是客户端负载均衡,
通过RestTemplate来访问接口服务的,
只要加@LoadBalanced注解来达到负载均衡是不是很简单

Ribbo负载均衡运行机制是什么?

Ribbo是一个基于HTTP和TCP的客户端负载均衡器,
当我们将Ribbon和Eureka一起使用时,Ribbon会从Eureka注册中心去获取服务端列表,
然后进行轮询访问以到达负载均衡的作用,客户端负载均衡中也需要心跳机制去维护服务端清单的有效性,
当然这个过程需要配合服务注册中心一起完成

常用的负载均衡策略

 1. RandomRule(随机策略)
 2. RoundRobinRule(轮询策略-默认策略)
 3. RetryRule(重试策略)
 4. WeightedResponseTimeRule(权重策略)

测试负载均衡

1.需要两个提供者项目

springcloud-provider-1(已有,项目端口9001)
springcloud-provider-2-项目端口是9003
和springcloud-provider-1项目一样但是就端口不一样,和自定义属性值不一样
相当于有springcloud-provide提供者两个实例,供消费者消费

2.启动两个提供者项目,查看注册中心

发现springcloud-provider服务up数量是2

6

3.启动Ribbo消费者来消费服务

不断刷新浏览器访问 http://localhost:9004/test
你会发现:

7

发现:
Ribbo 消费者会轮询消费注册列表的两个提供者服务

第六章-服务消费者(feign方式)

什么是 Feign ?

Feign是一套基于Netflix Feign实现的声明式服务调用客户端。
它使得编写Web服务客户端变得更加简单。通过创建接口并用注解来配置
它既可完成对Web服务接口的绑定。它具备可插拔的注解支持,
包括Feign注解、JAX-RS注解。它也支持可插拔的编码器和解码器。
也同时整合了Ribbon和Eureka来提供均衡负载的HTTP客户端实现。

总之,Feign是基于Ribbon实现,使得接口更加规范化,更有阅读性并且更加简单化,
也具有负载均衡的能力

创建 springcloud-feign 项目

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-demo</artifactId>
        <groupId>SpringCloud-demo</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-feign</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
  
    </dependencies>
</project>

配置application.yml

#配置服务名称及端口
spring:
  application:
    name: springcloud-feign
server:
  port: 9005
#将服务注册到注册中心
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:9000/eureka/
      #healthcheck:
       #enabled: true  #开启自定义健康检查
  instance:
    #eureka服务器在接收到最后一个心跳之后等待的时间,然后才能从列表中删除此实例 默认90s(开发环境)
    lease-expiration-duration-in-seconds: 10
    #eureka客户端需要向eureka服务器发送心跳的频率 默认30s (开发环境)
    lease-renewal-interval-in-seconds: 1

Feign启动类

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

Feign消费服务接口

定义一个feign接口,通过@ FeignClient(“服务名”),

来指定调用哪个服务。比如在代码中调用了springcloud-provider服务的“/test”接口,代码如下:

@FeignClient(value = "springcloud-provider")
public interface TestFeign {
    @RequestMapping(value = "/test")
    String testByFeign();
}

注意:服务名大小写无所谓,@FeignClient 会把接口类交给spring所管理

也就是说是可以@Autowired注入的

编写controller类调用服务

@RestController
public class TestController {
    @Autowired
    TestFeign testFeign;// 注入 Feign接口 
    @RequestMapping(value = "/test")
    public String test(){
        return testFeign.testByFeign();
    }
}

FeignApplication类启动测试

不断刷新浏览器地址 http://localhost:9005/test

8

从上面也能看的出来,Feign也是能消费服务,并且也有负载均衡
从而也证明了Feign是基于Ribbon实现
并使用注解接口使其更简单(@ FeignClient(“服务名”))

参数传递

上面是一个简单的调用案例,这个例子中没有涉及到参数的传递,那接下来看看参数的例子

再增加提供者三种情况的参数的服务接口,分别如下:

 // 测试带普通参数
    @RequestMapping("/testByParam")
    public String testByParam(String from) {
        return appName+"上线测试:"+name+":"+port+"来自:"+from;
    }

    // 测试带多个普通参数Map
    @RequestMapping("/testByMap")
    public String testByParam(@RequestParam Map<String,Object> map) {
        return appName+"上线测试:"+name+":"+port+"用户:"+map.get("name");
    }

    // 测试参数是对象的情况
    @RequestMapping("/testByRequestBody")
    public String testByRequestBody(@RequestBody  User user) {
        return appName+"上线测试:"+name+":"+port+"用户:"+user.getName();
    }

FeignClient 这边也增加对应的消费接口的方法

// 测试带普通参数
@RequestMapping(value = "/testByParam")
String testByParam(@RequestParam("from") String from);


// 测试带多个普通参数Map
@RequestMapping(value = "/testByMap")
String testByMap(Map<String,Object> map);


// 测试参数是对象的情况  @RequestBody  User user
@RequestMapping(value = "/testByRequestBody",method = RequestMethod.POST)
String testByRequestBody(@RequestBody User user);

注意,在SpringMVC中,@RequestParam,如果不指定value,则默认采用参数的名字作为其value,如上面的例子

但是在Feign中,这个value必须明确指定,否则会报错。

如果是pojo 实体类对象,服务提供者这方必须加上 @RequestBody注解

测试

9

Feign拦截器

可以再请求调用服务拦截做一些事情,比如日志记录、权限的判断

创建一个配置类,spirng会自动扫描的

@Configuration
public class FeignConfig {
 
    @Bean
    public RequestInterceptor getRequestInterceptor(){
        return new RequestInterceptor() {
            @Override
            public void apply(RequestTemplate requestTemplate) {
                /** 设置请求头信息 **/
                // requestTemplate.header("Content-Type", "application/json");
                // 可以做日志记录
                System.out.println("自定义拦截器");
            }
        };
    }

}

当然也能有多个拦截器,多加一个拦截器@bean就行了

@Configuration
public class FeignConfig {
 
    @Bean
    public RequestInterceptor getRequestInterceptor(){
        return new RequestInterceptor() {
            @Override
            public void apply(RequestTemplate requestTemplate) {
                /** 设置请求头信息 **/
                // requestTemplate.header("Content-Type", "application/json");
                // 可以做日志记录
                System.out.println("自定义拦截器-日志记录");
            }
        };
    }
	
	  @Bean
    public RequestInterceptor getRequestInterceptor2(){
        return new RequestInterceptor() {
            @Override
            public void apply(RequestTemplate requestTemplate) {
                /** 设置请求头信息 **/
                // requestTemplate.header("Content-Type", "application/json");
                // 可以做权限判断
                System.out.println("自定义拦截器2-权限判断");
            }
        };
    }

}

第七章-断路器(Hystrix)

Hystrix断路器的作用

服务断路容错:微服务往往服务众多,各服务之间相互调用,若消费者在调用提供者时出现由网络,
提供者服务自身问题等导致接口出现故障或延迟;此时消费者的请求不断增加,
务必会出现因等待响应而造成任务积压,线程无法释放,进一步导致服务的瘫痪。
出现雪崩效应
既然微服务架构存在这样的隐患,那么针对服务的容错性必然会进行服务降级,
依赖隔离,断路器等一线列的服务保护机制。

其实有点类似家用的保险丝作用

Feign没使用Hystrix断路器的情况

可以向提供者服务接口加上一段错误代码

   @RequestMapping("/test")
    public String test() {
        int a=1/0;// 除数不能为0
        return appName+"上线测试:"+name+":"+port;
    }

重新启动提供者,浏览器测试结果

10

调用了错误的接口,出现500错误的界面提示,这是我不希望看见的

希望看见调用错误,界面友好提示而不是报500错误界面

Feign使用Hystrix断路器的情况、

需要向springcloud-feign项目添加依赖

<!--添加Hystrix依赖 断路器容错保护 -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

修改springcloud-feign项目启动类

添加 @EnableHystrix 注解

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableHystrix//开启断路器功能
public class FeignApplication {
	public static void main(String[] args) {
		SpringApplication.run(FeignApplication.class, args);
	}
}

修改 application.yml 添加属性

#开启hystrix 指标
feign:
  hystrix:
    enabled: true

增加一个fallback错误回调类就行了

@Component
public class TestFeignFallback implements TestFeign {
    @Override
    public String testByFeign() {
        return "error";
    }

    @Override
    public String testByParam(String from) {
        return "error";
    }

    @Override
    public String testByMap(Map<String, Object> map) {
        return "error";
    }

    @Override
    public String testByRequestBody(User user) {
        return "error";
    }

  
}

关联fallback = TestFeignFallback.class 一旦错误就回调同名称的方法

@FeignClient(value = "springcloud-provider",fallback = TestFeignFallback.class)
public interface TestFeign {
    @RequestMapping(value = "/test")
    String testByFeign();

    // 测试带普通参数
    @RequestMapping(value = "/testByParam")
    String testByParam(@RequestParam("from") String from);


    // 测试带多个普通参数Map
    @RequestMapping(value = "/testByMap")
    String testByMap(Map<String,Object> map);


    // 测试参数是对象的情况  @RequestBody  User user
    @RequestMapping(value = "/testByRequestBody",method = RequestMethod.POST)
    String testByRequestBody(@RequestBody User user);

}

重启springcloud-feign项目,浏览器测试 http://localhost:9005/test

11

在ribbon使用断路器

需要向spirngcloud-ribbon-client项目添加依赖

<!--添加Hystrix依赖 断路器容错保护-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

修改spirngcloud-ribbon-client项目启动类

添加 @EnableHystrix 注解

@HystrixCommand(fallbackMethod = "error")和error方法

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

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

    @Autowired
    RestTemplate restTemplate;


    @RequestMapping(value = "/test")
    @HystrixCommand(fallbackMethod = "error")
    public String test(){
        return restTemplate.getForObject("http://springcloud-provider/test",String.class);
    }

    public String error() {
        return "error";
    }

一旦test接口报错就会降级调用error方法

第八章-Hystrix Dashboard监控面板

创建hystrixDashboard项目

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">
    <parent>
        <artifactId>SpringCloud-demo</artifactId>
        <groupId>SpringCloud-demo</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-hystrixDashboard</artifactId>

    <dependencies>
        <!-- 服务发现客户端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>

    </dependencies>
</project>

配置 application.yml

#将服务注册到注册中心
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:9000/eureka/
      #healthcheck:
      #enabled: true  #开启自定义健康检查
  instance:
    #eureka服务器在接收到最后一个心跳之后等待的时间,然后才能从列表中删除此实例 默认90s(开发环境)
    lease-expiration-duration-in-seconds: 10
    #eureka客户端需要向eureka服务器发送心跳的频率 默认30s (开发环境)
    lease-renewal-interval-in-seconds: 1
server:
  port: 9006
spring:
  application:
    name: springcloud-hystrixDashboard

创建 HystrixDashboardApplicat启动类

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

修改springcloud-feign项目

pom.xml

  <!--监控中心-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

增加 application.yml 属性(必须要加)

# 端点管理
management:
  endpoints:
    web:
      exposure:
        include: "*"
#开启hystrix 指标,若不开启 hystrixDashboard 没有记录 必须开启要不然不能实现断路器功能
feign:
  hystrix:
    enabled: true

启动项目测试

启动 springcloud-feign、hystrixDashboard、springcloud-provider-1 项目

 1.浏览器测试  http://localhost:9006/hystrix
 2.访问几次消费接口地址 http://localhost:9005/test
 3.如图所示输入监控地址:http://localhost:9005/actuator/hystrix.stream
 4.点击Monitor Stream按钮
 
 注意:要消费几次服务接口,要不然没有监控数据

12

监控数据展示

13

14

第九章-turbine(Hystrix监控数据集群)

当Hystrix消费者多个时需要把每一个消费监控信息整合在一个turbine集群面板上

创建 springcloud-turbine项目

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">
    <parent>
        <artifactId>SpringCloud-demo</artifactId>
        <groupId>SpringCloud-demo</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-turbine</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-turbine</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>
</project>

配置 application.yml

注意 指定了需要收集监控信息的服务名,多个以“,”进行区分

#将服务注册到注册中心
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:9000/eureka/
      #healthcheck:
      #enabled: true  #开启自定义健康检查
  instance:
    #eureka服务器在接收到最后一个心跳之后等待的时间,然后才能从列表中删除此实例 默认90s(开发环境)
    lease-expiration-duration-in-seconds: 10
    #eureka客户端需要向eureka服务器发送心跳的频率 默认30s (开发环境)
    lease-renewal-interval-in-seconds: 1
server:
  port: 9007
spring:
  application:
    name: springcloud-turbine
turbine:
  #指定了需要收集监控信息的服务名,多个以“,”进行区分
  appConfig: springcloud-feign
  clusterNameExpression: new String("default")
  combineHostPort: true

创建启动类

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

启动项目测试

0.启动注册中心
1.启动springcloud-feign
2.启动springcloud-provider-1
3.启动springcloud-hystrixDashboard
4.启动springcloud-turbine
 1.浏览器测试  http://localhost:9006/hystrix
 2.访问几次消费接口地址 http://localhost:9005/test
 3.如图所示输入监控地址:http://localhost:9007/turbine.stream
 4.点击Monitor Stream按钮
 
 注意:要消费几次服务接口,要不然没有监控数据

15

第十章-zuul-路由网关

zuul 介绍

我们知道微服务就是把一个大的项目拆分成很多小的独立服务项目,服务项目之间相互调用构建系统生态体系,那在这之间就有问题, 如何控制权限?如何分发路由?如何统一记录访问日志?为了解决这个问题就有了zuul网关,其实它可以理解成过滤器

为微服务架构提供了前门保护的作用,同时将权限控制这些较重的非业务逻辑内容迁移到服务路由层面,使得服务集群主体能够具备更高的可复用性和可测试性。

创建springcloud-zuul项目

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">
    <parent>
        <artifactId>SpringCloud-demo</artifactId>
        <groupId>SpringCloud-demo</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-zuul</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>
</project>

配置信息application.yml

#配置服务名称及端口
spring:
  application:
    name: springcloud-zuul
server:
  port: 9008
#将服务注册到注册中心
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:9000/eureka/
      #healthcheck:
       #enabled: true  #开启自定义健康检查
  instance:
    #eureka服务器在接收到最后一个心跳之后等待的时间,然后才能从列表中删除此实例 默认90s(开发环境)
    lease-expiration-duration-in-seconds: 10
    #eureka客户端需要向eureka服务器发送心跳的频率 默认30s (开发环境)
    lease-renewal-interval-in-seconds: 1

默认zuul-路由

zuul 路由,默认情况下,Eureka上所有注册的服务都会被Zuul创建映射关系来进行路由 如果映射规则我们什么都不写,系统也给我们提供了一套默认的配置规则,默认的配置 zuul.routes.应用服务名=/应用服务名/**

自定义路由

举例说明

zuul.routes.api-a.path=/api-a/**
zuul.routes.api-a.serviceId=springcloud-feign

我们说当我的访问地址符合/api-a/**规则的时候,会被自动定位到springcloud-feign服务上去,可以用下面一行代码来代替,如下:

zuul.routes.springcloud-feign=/api-a/**

也可以忽视不创建路由规则
zuul.ignored-services=springcloud-provider

定义过滤器

来个简单权限业务,如果有accessToken就放行,没有就提示无访问权限

package org.kd.filter;

import javax.servlet.http.HttpServletRequest;
 
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
public class AccessTokenFilter extends ZuulFilter {
	// run:过滤器的具体逻辑。默认是放行的
	// 通过ctx.setSendZuulResponse(false)令zuul过滤该请求,不对其进行路由,
	// 然后通过ctx.setResponseStatusCode(401)设置了其返回的错误码,
	// 也可以进一步优化比如,通过ctx.setResponseBody(body)对返回body内容进行编辑等。
	@Override
	public Object run() throws ZuulException {
		RequestContext ctx = RequestContext.getCurrentContext();
		HttpServletRequest request = ctx.getRequest();
 
		Object accessToken = request.getParameter("accessToken");
		System.out.println("accessToken:" + accessToken);
		if (accessToken == null) {
			ctx.setSendZuulResponse(false);
			ctx.setResponseStatusCode(401);
			ctx.addZuulResponseHeader("content-type","text/html;charset=utf-8");
			ctx.setResponseBody("无权访问-没有accessToken");
			return null;
		}
		return null;
	}
 
	// shouldFilter:判断该过滤器是否需要被执行。
	// true表示该过滤器对所有请求都会生效。
	// 实际运用中我们可以利用该函数来指定过滤器的有效范围。
	@Override
	public boolean shouldFilter() {
		return true;
	}
 
	// 过滤器的执行顺序。值越小越先执行
	@Override
	public int filterOrder() {
		return 0;
	}
 
	// filterType:过滤器的类型,它决定过滤器在请求的哪个生命周期中执行。
	// pre:可以在请求被路由之前调用
	// route:在路由请求时候被调用
	// post:在route和error过滤器之后被调用
	// error:处理请求时发生错误时被调用
	@Override
	public String filterType() {
		return "pre";
	}
 
}

创建启动类

@SpringBootApplication
@EnableZuulProxy// @EnableZuulProxy 自动加载过滤器bean
@EnableDiscoveryClient 
public class ZuulApplication {
	public static void main(String[] args) {
		SpringApplication.run(ZuulApplication.class, args);
	}	
}

设置过滤器

修改启动类,添加过滤器

@SpringBootApplication
@EnableZuulProxy// @EnableZuulProxy 自动加载过滤器bean
@EnableDiscoveryClient 
public class ZuulApplication {
	public static void main(String[] args) {
		SpringApplication.run(ZuulApplication.class, args);
	}	
   // AccessToken访问权限拦截
	@Bean
	public AccessTokenFilter accessTokenFilter() {
		return new AccessTokenFilter();
	}
}

浏览器启动测试

0.启动注册中心
1.启动springcloud-zuul项目
2.启动springcloud-provider-1项目
3.启动springcloud-feign项目

注意:需要zuul路由转发的

http://localhost:9008/springcloud-feign/test

16

http://localhost:9008/springcloud-feign/test?accessToken=100

17

Last Updated: 6/13/2019, 7:10:41 PM