單體應(yīng)用存在的問(wèn)題
- 隨著業(yè)務(wù)的發(fā)展,開(kāi)發(fā)變得越來(lái)越復(fù)雜悉患。
- 修改残家、新增某個(gè)功能,需要對(duì)整個(gè)系統(tǒng)進(jìn)行測(cè)試购撼、重新部署跪削。
- 一個(gè)模塊出現(xiàn)問(wèn)題,很可能導(dǎo)致整個(gè)系統(tǒng)崩潰迂求。
- 多個(gè)開(kāi)發(fā)團(tuán)隊(duì)同時(shí)對(duì)數(shù)據(jù)進(jìn)行管理碾盐,容易產(chǎn)生安全漏洞。
- 各個(gè)模塊使用同一種技術(shù)進(jìn)行開(kāi)發(fā)揩局,各個(gè)模塊很難根據(jù)實(shí)際情況選擇更合適的技術(shù)框架毫玖,局限性很大。
- 模塊內(nèi)容過(guò)于復(fù)雜,如果員工離職付枫,可能需要很長(zhǎng)時(shí)間才能完成工作交接烹玉。
分布式、集群
集群:一臺(tái)服務(wù)器無(wú)法負(fù)荷高并發(fā)的數(shù)據(jù)訪問(wèn)量阐滩,那么就設(shè)置十臺(tái)服務(wù)器一起分擔(dān)壓力二打,十臺(tái)不行就設(shè)置一百臺(tái)(物理層面)。很多人干同一件事情掂榔,來(lái)分?jǐn)倝毫Α?/p>
分布式:將一個(gè)復(fù)雜問(wèn)題拆分成若干個(gè)簡(jiǎn)單的小問(wèn)題继效,將一個(gè)大型的項(xiàng)目架構(gòu)拆分成若干個(gè)微服務(wù)來(lái)協(xié)同完成。(軟件設(shè)計(jì)層面)装获。將一個(gè)龐大的工作拆分成若干個(gè)小步驟瑞信,分別由不同的人完成這些小步驟,最終將所有的結(jié)果進(jìn)行整合實(shí)現(xiàn)大的需求穴豫。
服務(wù)治理的核心又三部分組成:服務(wù)提供者凡简、服務(wù)消費(fèi)者、注冊(cè)中心精肃。
在分布式系統(tǒng)架構(gòu)中秤涩,每個(gè)微服務(wù)在啟動(dòng)時(shí),將自己的信息存儲(chǔ)在注冊(cè)中心肋杖,叫做服務(wù)注冊(cè)溉仑。
服務(wù)消費(fèi)者從注冊(cè)中心獲取服務(wù)提供者的網(wǎng)絡(luò)信息,通過(guò)該信息調(diào)用服務(wù)状植,叫做服務(wù)發(fā)現(xiàn)。
Spring Cloud 的服務(wù)治理使用 Eureka 來(lái)實(shí)現(xiàn)怨喘,Eureka 是 Netflix 開(kāi)源的基于 REST 的服務(wù)治理解決方案津畸,Spring Cloud 集成了 Eureka,提供服務(wù)注冊(cè)和服務(wù)發(fā)現(xiàn)的功能必怜,可以和基于 Spring Boot 搭建的微服務(wù)應(yīng)用輕松完成整合肉拓,開(kāi)箱即用,Spring Cloud Eureka梳庆。
Spring Cloud Eureka
- Eureka Server暖途,注冊(cè)中心
- Eureka Client,所有要進(jìn)行注冊(cè)的微服務(wù)通過(guò) Eureka Client 連接到 Eureka Server膏执,完成注冊(cè)驻售。
Eureka Server代碼實(shí)現(xiàn)
- 創(chuàng)建父工程,pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.7.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 解決 JDK 9 以上沒(méi)有 JAXB API 的問(wèn)題 -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</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>
- 在父工程下創(chuàng)建 Module更米,pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
</dependencies>
- 創(chuàng)建配置文件 application.yml欺栗,添加 Eureka Server 相關(guān)配置。
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://localhost:8761/eureka/
屬性說(shuō)明
server.port
:當(dāng)前 Eureka Server 服務(wù)端口。
eureka.client.register-with-eureka
:是否將當(dāng)前的 Eureka Server 服務(wù)作為客戶端進(jìn)行注冊(cè)迟几。
eureka.client.fetch-fegistry
:是否獲取其他 Eureka Server 服務(wù)的數(shù)據(jù)消请。
eureka.client.service-url.defaultZone
:注冊(cè)中心的訪問(wèn)地址。
- 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class,args);
}
}
注解說(shuō)明:
@SpringBootApplication
:聲明該類(lèi)是 Spring Boot 服務(wù)的入口类腮。
@EnableEurekaServer
:聲明該類(lèi)是一個(gè) Eureka Server 微服務(wù)臊泰,提供服務(wù)注冊(cè)和服務(wù)發(fā)現(xiàn)功能,即注冊(cè)中心蚜枢。
Eureka Client 代碼實(shí)現(xiàn)
- 創(chuàng)建 Module 缸逃,pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
</dependencies>
- 創(chuàng)建配置文件 application.yml,添加 Eureka Client 相關(guān)配置
server:
port: 8010
spring:
application:
name: provider
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
屬性說(shuō)明:
spring.application.name
:當(dāng)前服務(wù)注冊(cè)在 Eureka Server 上的名稱祟偷。
eureka.client.service-url.defaultZone
:注冊(cè)中心的訪問(wèn)地址察滑。
eureka.instance.prefer-ip-address
:是否將當(dāng)前服務(wù)的 IP 注冊(cè)到 Eureka Server。
- 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class,args);
}
}
- 實(shí)體類(lèi)
package com.southwind.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private long id;
private String name;
private int age;
}
- Repository
package com.southwind.repository;
import com.southwind.entity.Student;
import java.util.Collection;
public interface StudentRepository {
public Collection<Student> findAll();
public Student findById(long id);
public void saveOrUpdate(Student student);
public void deleteById(long id);
}
- RepositoryImpl
package com.southwind.repository.impl;
import com.southwind.entity.Student;
import com.southwind.repository.StudentRepository;
import org.springframework.stereotype.Repository;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@Repository
public class StudentRepositoryImpl implements StudentRepository {
private static Map<Long,Student> studentMap;
static {
studentMap = new HashMap<>();
studentMap.put(1L,new Student(1L,"張三",22));
studentMap.put(2L,new Student(2L,"李四",23));
studentMap.put(3L,new Student(3L,"王五",24));
}
@Override
public Collection<Student> findAll() {
return studentMap.values();
}
@Override
public Student findById(long id) {
return studentMap.get(id);
}
@Override
public void saveOrUpdate(Student student) {
studentMap.put(student.getId(),student);
}
@Override
public void deleteById(long id) {
studentMap.remove(id);
}
}
- Handler
package com.southwind.controller;
import com.southwind.entity.Student;
import com.southwind.repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Collection;
@RestController
@RequestMapping("/student")
public class StudentHandler {
@Autowired
private StudentRepository studentRepository;
@GetMapping("/findAll")
public Collection<Student> findAll(){
return studentRepository.findAll();
}
@GetMapping("/findById/{id}")
public Student findById(@PathVariable("id") long id){
return studentRepository.findById(id);
}
@PostMapping("/save")
public void save(@RequestBody Student student){
studentRepository.saveOrUpdate(student);
}
@PutMapping("/update")
public void update(@RequestBody Student student){
studentRepository.saveOrUpdate(student);
}
@DeleteMapping("/deleteById/{id}")
public void deleteById(@PathVariable("id") long id){
studentRepository.deleteById(id);
}
}
RestTemplate 的使用
- 什么是 RestTemplate修肠?
RestTemplate 是 Spring 框架提供的基于 REST 的服務(wù)組件贺辰,底層是對(duì) HTTP 請(qǐng)求及響應(yīng)進(jìn)行了封裝,提供了很多訪問(wèn) RETS 服務(wù)的方法嵌施,可以簡(jiǎn)化代碼開(kāi)發(fā)饲化。
- 如何使用 RestTemplate?
1吗伤、創(chuàng)建 Maven 工程吃靠,pom.xml。
2足淆、創(chuàng)建實(shí)體類(lèi)
package com.southwind.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private long id;
private String name;
private int age;
}
3巢块、Handler
package com.southwind.controller;
import com.southwind.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.Collection;
@RestController
@RequestMapping("/rest")
public class RestHandler {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/findAll")
public Collection<Student> findAll(){
return restTemplate.getForEntity("http://localhost:8010/student/findAll",Collection.class).getBody();
}
@GetMapping("/findAll2")
public Collection<Student> findAll2(){
return restTemplate.getForObject("http://localhost:8010/student/findAll",Collection.class);
}
@GetMapping("/findById/{id}")
public Student findById(@PathVariable("id") long id){
return restTemplate.getForEntity("http://localhost:8010/student/findById/{id}",Student.class,id).getBody();
}
@GetMapping("/findById2/{id}")
public Student findById2(@PathVariable("id") long id){
return restTemplate.getForObject("http://localhost:8010/student/findById/{id}",Student.class,id);
}
@PostMapping("/save")
public void save(@RequestBody Student student){
restTemplate.postForEntity("http://localhost:8010/student/save",student,null).getBody();
}
@PostMapping("/save2")
public void save2(@RequestBody Student student){
restTemplate.postForObject("http://localhost:8010/student/save",student,null);
}
@PutMapping("/update")
public void update(@RequestBody Student student){
restTemplate.put("http://localhost:8010/student/update",student);
}
@DeleteMapping("/deleteById/{id}")
public void deleteById(@PathVariable("id") long id){
restTemplate.delete("http://localhost:8010/student/deleteById/{id}",id);
}
}
4、啟動(dòng)類(lèi)
package com.southwind;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class RestTemplateApplication {
public static void main(String[] args) {
SpringApplication.run(RestTemplateApplication.class,args);
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
服務(wù)消費(fèi)者 consumer
- 創(chuàng)建 Maven 工程巧号,pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
</dependencies>
- 創(chuàng)建配置文件 application.yml
server:
port: 8020
spring:
application:
name: consumer
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
- 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class,args);
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
- Handler
package com.southwind.controller;
import com.southwind.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.Collection;
@RestController
@RequestMapping("/consumer")
public class ConsumerHandler {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/findAll")
public Collection<Student> findAll(){
return restTemplate.getForEntity("http://localhost:8010/student/findAll",Collection.class).getBody();
}
@GetMapping("/findAll2")
public Collection<Student> findAll2(){
return restTemplate.getForObject("http://localhost:8010/student/findAll",Collection.class);
}
@GetMapping("/findById/{id}")
public Student findById(@PathVariable("id") long id){
return restTemplate.getForEntity("http://localhost:8010/student/findById/{id}",Student.class,id).getBody();
}
@GetMapping("/findById2/{id}")
public Student findById2(@PathVariable("id") long id){
return restTemplate.getForObject("http://localhost:8010/student/findById/{id}",Student.class,id);
}
@PostMapping("/save")
public void save(@RequestBody Student student){
restTemplate.postForEntity("http://localhost:8010/student/save",student,null).getBody();
}
@PostMapping("/save2")
public void save2(@RequestBody Student student){
restTemplate.postForObject("http://localhost:8010/student/save",student,null);
}
@PutMapping("/update")
public void update(@RequestBody Student student){
restTemplate.put("http://localhost:8010/student/update",student);
}
@DeleteMapping("/deleteById/{id}")
public void deleteById(@PathVariable("id") long id){
restTemplate.delete("http://localhost:8010/student/deleteById/{id}",id);
}
}
服務(wù)網(wǎng)關(guān)
Spring Cloud 集成了 Zuul 組件族奢,實(shí)現(xiàn)服務(wù)網(wǎng)關(guān)。
- 什么是 Zuul丹鸿?
Zuul 是 Netflix 提供的一個(gè)開(kāi)源的 API 網(wǎng)關(guān)服務(wù)器越走,是客戶端和網(wǎng)站后端所有請(qǐng)求的中間層,對(duì)外開(kāi)放一個(gè) API靠欢,將所有請(qǐng)求導(dǎo)入統(tǒng)一的入口廊敌,屏蔽了服務(wù)端的具體實(shí)現(xiàn)邏輯,Zuul 可以實(shí)現(xiàn)反向代理的功能门怪,在網(wǎng)關(guān)內(nèi)部實(shí)現(xiàn)動(dòng)態(tài)路由骡澈、身份認(rèn)證、IP 過(guò)濾薪缆、數(shù)據(jù)監(jiān)控等秧廉。
- 創(chuàng)建 Maven 工程伞广,pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
</dependencies>
- 創(chuàng)建配置文件 application.yml
server:
port: 8030
spring:
application:
name: gateway
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
zuul:
routes:
provider: /p/**
屬性說(shuō)明:
zuul.routes.provider
:給服務(wù)提供者 provider 設(shè)置映射
- 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@EnableZuulProxy
@EnableAutoConfiguration
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class,args);
}
}
注解說(shuō)明:
@EnableZuulProxy
:包含了 @EnableZuulServer
,設(shè)置該類(lèi)是網(wǎng)關(guān)的啟動(dòng)類(lèi)疼电。
@EnableAutoConfiguration
:可以幫助 Spring Boot 應(yīng)用將所有符合條件的 @Configuration
配置加載到當(dāng)前 Spring Boot 創(chuàng)建并使用的 IoC 容器中嚼锄。
- Zuul 自帶了負(fù)載均衡功能,修改 provider 的代碼蔽豺。
package com.southwind.controller;
import com.southwind.entity.Student;
import com.southwind.repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import java.util.Collection;
@RestController
@RequestMapping("/student")
public class StudentHandler {
@Autowired
private StudentRepository studentRepository;
@Value("${server.port}")
private String port;
@GetMapping("/findAll")
public Collection<Student> findAll(){
return studentRepository.findAll();
}
@GetMapping("/findById/{id}")
public Student findById(@PathVariable("id") long id){
return studentRepository.findById(id);
}
@PostMapping("/save")
public void save(@RequestBody Student student){
studentRepository.saveOrUpdate(student);
}
@PutMapping("/update")
public void update(@RequestBody Student student){
studentRepository.saveOrUpdate(student);
}
@DeleteMapping("/deleteById/{id}")
public void deleteById(@PathVariable("id") long id){
studentRepository.deleteById(id);
}
@GetMapping("/index")
public String index(){
return "當(dāng)前端口:"+this.port;
}
}
Ribbon 負(fù)載均衡
- 什么是 Ribbon区丑?
Spring Cloud Ribbon 是一個(gè)負(fù)載均衡解決方案,Ribbon 是 Netflix 發(fā)布的負(fù)載均衡器修陡,Spring Cloud Ribbon 是基于 Netflix Ribbon 實(shí)現(xiàn)的沧侥,是一個(gè)用于對(duì) HTTP 請(qǐng)求進(jìn)行控制的負(fù)載均衡客戶端。
在注冊(cè)中心對(duì) Ribbon 進(jìn)行注冊(cè)之后魄鸦,Ribbon 就可以基于某種負(fù)載均衡算法宴杀,如輪詢、隨機(jī)拾因、加權(quán)輪詢旺罢、加權(quán)隨機(jī)等自動(dòng)幫助服務(wù)消費(fèi)者調(diào)用接口,開(kāi)發(fā)者也可以根據(jù)具體需求自定義 Ribbon 負(fù)載均衡算法绢记。實(shí)際開(kāi)發(fā)中扁达,Spring Cloud Ribbon 需要結(jié)合 Spring Cloud Eureka 來(lái)使用,Eureka Server 提供所有可以調(diào)用的服務(wù)提供者列表蠢熄,Ribbon 基于特定的負(fù)載均衡算法從這些服務(wù)提供者中選擇要調(diào)用的具體實(shí)例跪解。
- 創(chuàng)建 Module,pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
</dependencies>
- 創(chuàng)建配置文件 application.yml
server:
port: 8040
spring:
application:
name: ribbon
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
- 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class RibbonApplication {
public static void main(String[] args) {
SpringApplication.run(RibbonApplication.class,args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
@LoadBalanced
:聲明一個(gè)基于 Ribbon 的負(fù)載均衡签孔。
- Handler
package com.southwind.controller;
import com.southwind.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.Collection;
@RestController
@RequestMapping("/ribbon")
public class RibbonHandler {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/findAll")
public Collection<Student> findAll(){
return restTemplate.getForObject("http://provider/student/findAll",Collection.class);
}
@GetMapping("/index")
public String index(){
return restTemplate.getForObject("http://provider/student/index",String.class);
}
}
Feign
- 什么是 Feign叉讥?
與 Ribbon 一樣,F(xiàn)eign 也是由 Netflix 提供的饥追,F(xiàn)eign 是一個(gè)聲明式节吮、模版化的 Web Service 客戶端,它簡(jiǎn)化了開(kāi)發(fā)者編寫(xiě) Web 服務(wù)客戶端的操作判耕,開(kāi)發(fā)者可以通過(guò)簡(jiǎn)單的接口和注解來(lái)調(diào)用 HTTP API,Spring Cloud Feign翘骂,它整合了 Ribbon 和 Hystrix壁熄,具有可插拔、基于注解碳竟、負(fù)載均衡草丧、服務(wù)熔斷等一系列便捷功能。
相比較于 Ribbon + RestTemplate 的方式莹桅,F(xiàn)eign 大大簡(jiǎn)化了代碼的開(kāi)發(fā)昌执,F(xiàn)eign 支持多種注解烛亦,包括 Feign 注解、JAX-RS 注解懂拾、Spring MVC 注解等煤禽,Spring Cloud 對(duì) Feing 進(jìn)行了優(yōu)化,整合了 Ribbon 和 Eureka岖赋,從而讓 Feign 的使用更加方便檬果。
- Ribbon 和 Feign 的區(qū)別
Ribbon 是一個(gè)通用的 HTTP 客戶端工具,F(xiàn)eign 是基于 Ribbon 實(shí)現(xiàn)的唐断。
- Feign 的tedian
1选脊、Feign 是一個(gè)聲明式的 Web Service 客戶端。
2脸甘、支持 Feign 注解恳啥、Spring MVC 注解、JAX-RS 注解丹诀。
3钝的、Feign 基于 Ribbon 實(shí)現(xiàn),使用起來(lái)更加簡(jiǎn)單忿墅。
4扁藕、Feign 集成了 Hystrix,具備服務(wù)熔斷的功能疚脐。
- 創(chuàng)建 Module亿柑,pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
</dependencies>
- 創(chuàng)建配置文件 application.yml
server:
port: 8050
spring:
application:
name: feign
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
- 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
public class FeignApplication {
public static void main(String[] args) {
SpringApplication.run(FeignApplication.class,args);
}
}
- 創(chuàng)建聲明式接口
package com.southwind.feign;
import com.southwind.entity.Student;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.Collection;
@FeignClient(value = "provider")
public interface FeignProviderClient {
@GetMapping("/student/findAll")
public Collection<Student> findAll();
@GetMapping("/student/index")
public String index();
}
- Handler
package com.southwind.controller;
import com.southwind.entity.Student;
import com.southwind.feign.FeignProviderClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collection;
@RestController
@RequestMapping("/feign")
public class FeignHandler {
@Autowired
private FeignProviderClient feignProviderClient;
@GetMapping("/findAll")
public Collection<Student> findAll(){
return feignProviderClient.findAll();
}
@GetMapping("/index")
public String index(){
return feignProviderClient.index();
}
}
- 服務(wù)熔斷,application.yml 添加熔斷機(jī)制棍弄。
server:
port: 8050
spring:
application:
name: feign
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
feign:
hystrix:
enabled: true
feign.hystrix.enabled
:是否開(kāi)啟熔斷器望薄。
- 創(chuàng)建 FeignProviderClient 接口的實(shí)現(xiàn)類(lèi) FeignError,定義容錯(cuò)處理邏輯呼畸,通過(guò)
@Component
注解將 FeignError 實(shí)例注入 IoC 容器中痕支。
package com.southwind.feign.impl;
import com.southwind.entity.Student;
import com.southwind.feign.FeignProviderClient;
import org.springframework.stereotype.Component;
import java.util.Collection;
@Component
public class FeignError implements FeignProviderClient {
@Override
public Collection<Student> findAll() {
return null;
}
@Override
public String index() {
return "服務(wù)器維護(hù)中......";
}
}
- 在 FeignProviderClient 定義處通過(guò)
@FeignClient
的 fallback 屬性設(shè)置映射。
package com.southwind.feign;
import com.southwind.entity.Student;
import com.southwind.feign.impl.FeignError;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.Collection;
@FeignClient(value = "provider",fallback = FeignError.class)
public interface FeignProviderClient {
@GetMapping("/student/findAll")
public Collection<Student> findAll();
@GetMapping("/student/index")
public String index();
}
Hystrix 容錯(cuò)機(jī)制
在不改變各個(gè)微服務(wù)調(diào)用關(guān)系的前提下蛮原,針對(duì)錯(cuò)誤情況進(jìn)行預(yù)先處理卧须。
- 設(shè)計(jì)原則
1、服務(wù)隔離機(jī)制
2儒陨、服務(wù)降級(jí)機(jī)制
3花嘶、熔斷機(jī)制
4、提供實(shí)時(shí)的監(jiān)控和報(bào)警功能
5蹦漠、提供實(shí)時(shí)的配置修改功能
Hystrix 數(shù)據(jù)監(jiān)控需要結(jié)合 Spring Boot Actuator 來(lái)使用椭员,Actuator 提供了對(duì)服務(wù)的健康健康、數(shù)據(jù)統(tǒng)計(jì)笛园,可以通過(guò) hystrix.stream 節(jié)點(diǎn)獲取監(jiān)控的請(qǐng)求數(shù)據(jù)隘击,提供了可視化的監(jiān)控界面侍芝。
- 創(chuàng)建 Maven,pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.0.7.RELEASE</version>
</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.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
</dependencies>
- 創(chuàng)建配置文件 application.yml
server:
port: 8060
spring:
application:
name: hystrix
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
feign:
hystrix:
enabled: true
management:
endpoints:
web:
exposure:
include: 'hystrix.stream'
- 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
@EnableCircuitBreaker
@EnableHystrixDashboard
public class HystrixApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixApplication.class,args);
}
}
注解說(shuō)明:
@EnableCircuitBreaker
:聲明啟用數(shù)據(jù)監(jiān)控
@EnableHystrixDashboard
:聲明啟用可視化數(shù)據(jù)監(jiān)控
- Handler
package com.southwind.controller;
import com.southwind.entity.Student;
import com.southwind.feign.FeignProviderClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collection;
@RestController
@RequestMapping("/hystrix")
public class HystrixHandler {
@Autowired
private FeignProviderClient feignProviderClient;
@GetMapping("/findAll")
public Collection<Student> findAll(){
return feignProviderClient.findAll();
}
@GetMapping("/index")
public String index(){
return feignProviderClient.index();
}
}
- 啟動(dòng)成功之后埋同,訪問(wèn)
http://localhost:8060/actuator/hystrix.stream
可以監(jiān)控到請(qǐng)求數(shù)據(jù)州叠, - 訪問(wèn)
http://localhost:8060/hystrix
,可以看到可視化的監(jiān)控界面莺禁,輸入要監(jiān)控的地址節(jié)點(diǎn)即可看到該節(jié)點(diǎn)的可視化數(shù)據(jù)監(jiān)控留量。
Spring Cloud 配置中心
Spring Cloud Config,通過(guò)服務(wù)端可以為多個(gè)客戶端提供配置服務(wù)哟冬。Spring Cloud Config 可以將配置文件存儲(chǔ)在本地楼熄,也可以將配置文件存儲(chǔ)在遠(yuǎn)程 Git 倉(cāng)庫(kù),創(chuàng)建 Config Server浩峡,通過(guò)它管理所有的配置文件可岂。
本地文件系統(tǒng)
- 創(chuàng)建 Maven 工程,pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
</dependencies>
- 創(chuàng)建 application.yml
server:
port: 8762
spring:
application:
name: nativeconfigserver
profiles:
active: native
cloud:
config:
server:
native:
search-locations: classpath:/shared
注解說(shuō)明
profiles.active
:配置文件的獲取方式
cloud.config.server.native.search-locations
:本地配置文件存放的路徑
- resources 路徑下創(chuàng)建 shared 文件夾翰灾,并在此路徑下創(chuàng)建 configclient-dev.yml缕粹。
server:
port: 8070
foo: foo version 1
- 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication
@EnableConfigServer
public class NativeConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(NativeConfigServerApplication.class,args);
}
}
注解說(shuō)明
@EnableConfigServer
:聲明配置中心。
創(chuàng)建客戶端讀取本地配置中心的配置文件
- 創(chuàng)建 Maven 工程纸淮,pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
</dependencies>
- 創(chuàng)建 bootstrap.yml平斩,配置讀取本地配置中心的相關(guān)信息。
spring:
application:
name: configclient
profiles:
active: dev
cloud:
config:
uri: http://localhost:8762
fail-fast: true
注解說(shuō)明
cloud.config.uri
:本地 Config Server 的訪問(wèn)路徑
cloud.config.fail-fase
:設(shè)置客戶端優(yōu)先判斷 Config Server 獲取是否正常咽块。
通過(guò)spring.application.name
結(jié)合spring.profiles.active
拼接目標(biāo)配置文件名绘面,configclient-dev.yml,去 Config Server 中查找該文件侈沪。
- 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class NativeConfigClientApplication {
public static void main(String[] args) {
SpringApplication.run(NativeConfigClientApplication.class,args);
}
}
- Handler
package com.southwind.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/native")
public class NativeConfigHandler {
@Value("${server.port}")
private String port;
@Value("${foo}")
private String foo;
@GetMapping("/index")
public String index(){
return this.port+"-"+this.foo;
}
}
Spring Cloud Config 遠(yuǎn)程配置
- 創(chuàng)建配置文件揭璃,上傳至 GitHub
server:
port: 8070
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
spring:
application:
name: configclient
- 創(chuàng)建 Config Server,新建 Maven 工程亭罪,pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
</dependencies>
- 創(chuàng)建配置文件 application.yml
server:
port: 8888
spring:
application:
name: configserver
cloud:
config:
server:
git:
uri: https://github.com/southwind9801/aispringcloud.git
searchPaths: config
username: root
password: root
label: master
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
- 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class,args);
}
}
創(chuàng)建 Config Client
- 創(chuàng)建 Maven 工程瘦馍,pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
</dependencies>
- 創(chuàng)建 bootstrap.yml
spring:
cloud:
config:
name: configclient
label: master
discovery:
enabled: true
service-id: configserver
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
注解說(shuō)明
spring.cloud.config.name
:當(dāng)前服務(wù)注冊(cè)在 Eureka Server 上的名稱,與遠(yuǎn)程倉(cāng)庫(kù)的配置文件名對(duì)應(yīng)应役。
spring.cloud.config.label
:Git Repository 的分支情组。
spring.cloud.config.discovery.enabled
:是否開(kāi)啟 Config 服務(wù)發(fā)現(xiàn)支持。
spring.cloud.config.discovery.service-id
:配置中心在 Eureka Server 上注冊(cè)的名稱箩祥。
- 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ConfigClientApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigClientApplication.class,args);
}
}
- Handler
package com.southwind.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/hello")
public class HelloHandler {
@Value("${server.port}")
private String port;
@GetMapping("/index")
public String index(){
return this.port;
}
}
服務(wù)跟蹤
Spring Cloud Zipkin
Zipkin 是一個(gè)可以采集并且跟蹤分布式系統(tǒng)中請(qǐng)求數(shù)據(jù)的組件呻惕,讓開(kāi)發(fā)者可以更加直觀的監(jiān)控到請(qǐng)求在各個(gè)微服務(wù)所耗費(fèi)的時(shí)間等,Zipkin:Zipkin Server滥比、Zipkin Client。
創(chuàng)建 Zipkin Server
- 創(chuàng)建 Maven 工程做院,pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-server</artifactId>
<version>2.9.4</version>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-autoconfigure-ui</artifactId>
<version>2.9.4</version>
</dependency>
</dependencies>
- 創(chuàng)建配置文件 application.yml
server:
port: 9090
- 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import zipkin.server.internal.EnableZipkinServer;
@SpringBootApplication
@EnableZipkinServer
public class ZipkinApplication {
public static void main(String[] args) {
SpringApplication.run(ZipkinApplication.class,args);
}
}
注解說(shuō)明
@EnableZipkinServer
:聲明啟動(dòng) Zipkin Server
創(chuàng)建 Zipkin Client
- 創(chuàng)建 Maven 工程盲泛,pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
</dependencies>
- 創(chuàng)建配置文件 application.yml
server:
port: 8090
spring:
application:
name: zipkinclient
sleuth:
web:
client:
enabled: true
sampler:
probability: 1.0
zipkin:
base-url: http://localhost:9090/
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
屬性說(shuō)明
spring.sleuth.web.client.enabled
:設(shè)置開(kāi)啟請(qǐng)求跟蹤
spring.sleuth.sampler.probability
:設(shè)置采樣比例濒持,默認(rèn)是 1.0
srping.zipkin.base-url
:Zipkin Server 地址
- 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ZipkinClientApplication {
public static void main(String[] args) {
SpringApplication.run(ZipkinClientApplication.class,args);
}
}
- Handler
package com.southwind.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/zipkin")
public class ZipkinHandler {
@Value("${server.port}")
private String port;
@GetMapping("/index")
public String index(){
return this.port;
}
}