在微服务架构里,业务会被拆分成一个个的独立的服务,服务与服务之间通讯都是采用HTTP RestFul的。spring cloud有两种服务调用方式,一种使Ribbon+restTemplate,另一种使feign。这里先记录一下Ribbon
惯例,先创建一个springboot服务,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>
<artifactId>hello-spring-cloud-web-admin-ribbon</artifactId>
<packaging>jar</packaging>
<name>hello-spring-cloud-web-admin-ribbon</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>com.yuu</groupId>
<artifactId>hello-spring-cloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../hello-spring-cloud-dependencies/pom.xml</relativePath>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</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-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--解决thymeleaf模板引擎一定要严格执行的h5校验问题-->
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR2</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>
这里重点使用依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
yml配置:
spring:
application:
name: hello-spring-cloud-web-admin-ribbon
thymeleaf:
cache: false
mode: LEGACYHTML5
encodeing: UTF-8
servlet:
content-type: text/html
server:
port: 8764
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
这里关于thymeleaf的配置,用到thymeleaf了就配置,没用到不配置也可,对服务核心内容没什么影响
启动类:
package com.yuu.hello.spring.cloud.web.admin.ribbon;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
@EnableDiscoveryClient
@SpringBootApplication
public class WebAdminRibbonApplication {
public static void main(String[] args){
SpringApplication.run(WebAdminRibbonApplication.class,args);
}
}
@EnableDiscoveryClient注解与@EnableEurekaClient功能使一样的,@EnableEurekaClient功能相对单一些,只适用于eureka的注册中心
调用服务,首先创建一个配置类,用以返回一个RestTemplate类的bean,RestTemplate类是用于调用服务的类,它的优点是简化了http的通信方式,统一了restful请求的标准
package com.yuu.hello.spring.cloud.web.admin.ribbon.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfiguration {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
@LoadBalanced的作用是负载均衡,当被调用的服务是以集群形式存在的时候,RestTemplate会以负载均衡的方式调用服务
service类
package com.yuu.hello.spring.cloud.web.admin.ribbon.service;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class AdminService {
@Autowired
RestTemplate restTemplate;
public String sayHi(String message){
return restTemplate.getForObject("http://hello-spring-cloud-service-admin/hi?message="+message,String.class);
}
}
RestTemplate 在调用服务请求的时候,会以目标服务名称的方式请求服务,这样节省了维护服务地址的成本
controller类
package com.yuu.hello.spring.cloud.web.admin.ribbon.controller;
import com.yuu.hello.spring.cloud.web.admin.ribbon.service.AdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AdminController {
@Autowired
private AdminService adminService;
@GetMapping("hi")
public String sayHi(String message){
return adminService.sayHi(message);
}
}
由于网络原因或服务自身原因,服务并不能保证100%可用,如果单个服务出现故障,调用这个服务的线程就会被阻塞,此时涌入大量的请求,会迅速消耗servlet线程资源,导致服务瘫痪,因为服务间相互依赖,故障会在服务间相互传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的雪崩效应。
为防止雪崩效应,需要引入熔断器
springcloud引入了Netflix出品的hystrix
ribbon中增加熔断器步骤如下:
在pom文件中增加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
在启动类上增加@EnableHystrix用以开启熔断器
@EnableDiscoveryClient
@SpringBootApplication
@EnableHystrix
public class WebAdminRibbonApplication {
public static void main(String[] args){
SpringApplication.run(WebAdminRibbonApplication.class,args);
}
}
在service类调用服务请求的方法上增加注解@HystrixCommand,参数含义是调用失败时回调的方法名称
@HystrixCommand(fallbackMethod = "hiError")
public String sayHi(String message){
return restTemplate.getForObject("http://hello-spring-cloud-service-admin/hi?message="+message,String.class);
}
回调方法
public String hiError(String message){
return String.format("Request is bad, your message is : %s",message);
}