1.Spring Cloud
1.微服务产⽣的背景
单体应⽤存在的问题:
- 随着业务的发展,开发变得越来越复杂。
- 修改、新增某个功能,需要对整个系统进⾏测试,重写部署。
- ⼀个模块出现问题,很可能导致整个系统崩溃。
- 多团队同时对数据进⾏管理,容易产⽣安全漏洞。
- 各个模块使⽤同⼀种技术框架,局限性太⼤,很难根据业务选择最适合的技术架构。
- 模块内容太复杂,如果员⼯离职,可能需要很⻓时间才能完成任务交接。
为了解决上述问题,微服务架构应运⽽⽣,简单来说,微服务就是将⼀个单体应⽤拆分成若⼲个⼩型服务,协同完成系统功能的⼀种架构模式,在系统架构层⾯进⾏解耦合,将⼀个复杂问题拆分成若⼲个简单问题。
这样的好处是对于每⼀个简单问题,开发、维护、部署的难度就降低了很多,可以实现⾃治,可以⾃主选择最适合的技术框架,提⾼了项⽬开发的灵活性。
微服务架构不仅是简单的拆分,拆分之后的各个微服务之间还要进⾏通信,否则就⽆法协同完成需求。微服务之间只需要制定统⼀的协议即可,⾄于每个微服务使⽤什么技术框架来完成,统统不需要关⼼。
这种松耦合的⽅式使得开发、部署都变得更加灵活,同时系统更容易扩展,降低了开发、运维的难度。
2.微服务的优点
- 各个服务之间实现了松耦合,彼此之间不需要关注对⽅是⽤什么语⾔开发,什么技术开发,只需要保证⾃⼰的接⼝可以正常访问即可,通过标准协议访问其他接⼝即可。
- 各个微服务之间独⽴⾃治,只需要专注于做好⾃⼰的业务,开发和维护不会影响到其他的微服务。
- 微服务是⼀种去中⼼化的架构⽅式,相当于⽤零件拼接⼀台机器,如果某个零件出现问题,可以随时进⾏替换从⽽保证机器的正常运⾏。
3.微服务的不⾜
- 如果某个系统的远程调⽤出现问题,导致微服务不可⽤,就有可能产⽣级联反应,造成整个系统的崩溃。
- 如果某个需求需要调⽤多个微服务,如何来保证数据的⼀致性。
- 相⽐较于单体应⽤,微服务的学习难度会增加,对于新加⼊团队的员⼯来讲,如何快速掌握上⼿微服务架构,是⼀个问题。
4.微服务设计原则
从⼤到⼩,提炼出核⼼需求,搞清楚服务间的交互关系,先拆分成粒度较⼤的服务,然后再根据具体的业务需求逐步细化服务粒度,最终形成⼀套合理的微服务系统架构。
- 服务粒度不能太⼩也不能太⼤,提炼核⼼需求,根据服务间的交互关系找到最合理的服务粒度。
- 各个微服务的功能职责尽量单⼀,避免出现多个服务处理同⼀个需求。
- 各个微服务之间要相互独⽴、⾃治,⾃主开发、⾃主测试、⾃主部署、⾃主维护。
- 保证数据的独⽴性,各个微服务独⽴管理其业务模型下的数据。
- 使⽤ RESTful 协议完成微服务之间的协作任务,数据交互采⽤ JSON 格式,⽅便调⽤和整合。
5.微服务架构的核⼼组件
- 服务治理 : 服务注册 服务发现
提供服务的叫做服务提供者,调⽤服务的叫做服务消费者
- 服务负载均衡
- 服务⽹关
- 微服务容错机制
- 分布式配置
- 服务监控
6.解决⽅案
Spring Cloud
微服务是⼀种分布式软件架构设计⽅式,具体的落地⽅案有很多,Dubbo、Spring Boot/SpringCloud、Motan 等等,Spring Cloud 基于 Spring Boot 使得整体的开发、配置、部署都⾮常⽅便,可以快速搭建基于微服务的分布式应⽤,Spring Cloud 相当于微服务各个组件的集⼤成者。
7.Spring Boot 和 Spring Cloud 的关系
Spring Boot 快速搭建基础系统,Spring Cloud 在此基础上实现分布式系统中的公共组件,如服务注册、服务发现、配置管理、熔断器、控制总线等,服务调⽤⽅式是基于 REST API
8.搭建微服务系统的核⼼中枢
服务治理的核⼼组件:
- 服务提供者
- 服务消费者
- 注册中⼼
分布式系统架构中,每个微服务在启动时,将⾃⼰的信息存储在注册中⼼,服务注册。
服务消费者从注册中⼼查询服务提供者的⽹络信息,并通过此信息调⽤服务提供者的接⼝,服务发现。
注册中⼼管理各个微服务:通过⼼跳机制,每隔⼀定的时间微服务会向注册中⼼进⾏汇报,如果注册中⼼⻓时间⽆法与某个微服务通信,就会⾃动销毁该服务。
当某个微服务的⽹络信息发⽣变化时,会重新注册。
服务提供者、服务消费者、注册中⼼的关联:
- 启动注册中⼼
- 服务提供者启动,在注册中⼼注册⼀个可以提供服务的实例。
- 服务消费者启动,在注册中⼼订阅需要调⽤的服务。
- 注册中⼼将服务提供者的信息推送给服务调⽤者。
- 服务调⽤者通过相关信息(IP、端⼝)调⽤服务提供者的服务。
注册中⼼核⼼模块:
- 服务注册表
- 服务注册
- 服务发现
- 服务检查
Spring Cloud 的服务治理可以使⽤ Eureka 组件
9.什么是 Eureka?
Spring Cloud Eureka,提供服务注册和服务发现功能。
参考大神的图
如上图所示:库存服务,仓储服务,积分服务,都有一个Eureka Client组件组件,这个专门这个服务的信息注册到Eureka Server中,说白了就是告诉Eureka Server,自己在哪台机器上,监听那个端口,而Eureka 是一个注册中心,里面有一个注册表,保存了各个服务器的机器和端口,
订单服务里面有一个Eureka Client组件组件,Eureka Client组件会问一下:库存在那台服务器上,监听的端口号是哪个,仓储服务呢?积分服务呢?然后就可以把这些相关信息从Eureka Server的注册表中拉取到自己本地缓存起来。
这时候如果订单服务想要调用库存服务,不就可以找自己本地Eureka Client问题下库存服务在那台机器上,监听哪个端口吗?收到响应后,紧接着就可以发送一个请求过去,调用库存服务扣减库存的那个接口!同理,如果订单服务要调用仓储服务、积分服务,也是如法炮制。
所以总结下:
**Eureka service:**注册中心,里面有一个注册表,保存了各个服务所在的机器和端口号
**Eurake Client:**负责将这个服务的信息注册到Eureka Server中
2.代码实现
1.创建 Maven ⽗⼯程,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>
<!-- JDK9 -->
<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>
2.在⽗⼯程⽬录下创建 Module,实现 Eureka Server,pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
- 在Eureka Server中配置application.yml
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://localhost:8761/eureka/
4.创建启动类
package com.ag;
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);
}
}
5.启动,访问 http://localhost:8761,可以看到如下界⾯,启动成功。
注册第⼀个微服务
服务提供者和服务消费者都是通过 Eureka Client 连接到 Eureka Server 完成注册
1.创建 Modelu,实现 Eureka Client。
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
2.application.yml
server:
port: 8010
spring:
application:
name: provider
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
3.创建启动类
package com.ag;
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);
}
}
4.实体类
package com.ag.entity;
import lombok.Data;
@Data
public class Student {
private Integer id;
private String name;
}
5.创建 Repository
package com.ag.repository;
import com.ag.entity.Student;
import java.util.Collection;
public interface StudentRepository {
public Collection<Student> findAll();
public Student findById(Integer id);
public void saveOrUpdate(Student student);
public void deleteById(Integer id);
}
package com.ag.repository.impl;
import com.ag.entity.Student;
import com.ag.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<Integer,Student> map;
static {
map = new HashMap<>();
map.put(1,new Student(1,"张三"));
map.put(2,new Student(2,"李四"));
map.put(3,new Student(3,"王五"));
}
@Override
public Collection<Student> findAll() {
return map.values();
}
@Override
public Student findById(Integer id) {
return map.get(id);
}
@Override
public void saveOrUpdate(Student student) {
map.put(student.getId(),student);
}
@Override
public void deleteById(Integer id) {
map.remove(id);
}
}
6.StudentHandler
package com.ag.controller;
import com.ag.entity.Student;
import com.ag.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") Integer 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") Integer id){
studentRepository.deleteById(id);
}
}
先启动server 在启动provider
3.RestTemplate
通过 RestTemplate 可以实现不同微服务之间的调⽤。
RestTemplate 是 Spring 框架提供的⼀种基于 RESTful 的服务组件,底层对 HTTP 请求及响应进⾏了封装,提供了很多访问远程 REST 服务的⽅法,可以简化代码的开发。
1.创建 Maven ⼯程,pom.xml
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<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>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
2.创建 User 类
package com.ag.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String name;
}
3.创建 UserRepository 接⼝及实现类
package com.ag.repository;
import com.ag.entity.User;
import java.util.Collection;
public interface UserRepository {
public Collection<User> findAll();
public User findById(Integer id);
public void saveOrUpdate(User user);
public void deleteById(Integer id);
}
package com.ag.repository.impl;
import com.ag.entity.User;
import com.ag.repository.UserRepository;
import org.springframework.stereotype.Repository;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@Repository
public class UserRepositoryImpl implements UserRepository {
private static Map<Integer,User> map;
static {
map=new HashMap<>();
map.put(1,new User(1,"tutu01"));
map.put(2,new User(2,"tutu02"));
map.put(3,new User(3,"tutu03"));
}
@Override
public Collection<User> findAll() {
return map.values();
}
@Override
public User findById(Integer id) {
return map.get(id);
}
@Override
public void saveOrUpdate(User user) {
map.put(user.getId(),user);
}
@Override
public void deleteById(Integer id) {
map.remove(id);
}
}
4.创建 UserHandler
package com.ag.controller;
import com.ag.entity.User;
import com.ag.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Collection;
@RestController
@RequestMapping("/user")
public class UserHandler {
@Autowired
private UserRepository userRepository;
@GetMapping("/findAll")
public Collection<User> findAll(){
return userRepository.findAll();
}
@GetMapping("/findById/{id}")
public User findById(@PathVariable("id") Integer id){
return userRepository.findById(id);
}
@PostMapping("/save")
public void save(@RequestBody User user){
userRepository.saveOrUpdate(user);
}
@PutMapping("/update")
public void update(@RequestBody User user){
userRepository.saveOrUpdate(user);
}
@DeleteMapping("/deleteById/{id}")
public void deleteById(@PathVariable("id") Integer id){
userRepository.deleteById(id);
}
}
5.创建启动类
package com.ag;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
1.使⽤ RestTemplate 访问 REST 服务
RestTemplate 底层对 HTTP 请求及响应进⾏了封装,提供了很多访问远程 REST 服务的⽅法,基于它的这个特性,我们可以实现不同微服务之间的调⽤。
什么是RestTemplate?
RestTemplate提供了多种便捷访问远程Http服务的方法,是一种简单便捷的访问restful服务模板类,是spring提供的用于访问Rest服务的客户端模板工具集
RestTemplate使用:
使用restTemplate访问restful接口非常的简单粗暴无脑。
(url,requestMap,ResponseBean.class)这是三个参数分别代表
REST请求地址、请求参数、HTTP响应转换被转换成的对象类型。
1.将 RestTemplate 的实例化对象通过 @Bean 注⼊ IoC
package com.ag.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class MyConfig {
@Bean
public RestTemplate template(){
return new RestTemplate();
}
}
2.创建 RestHandler
package com.ag.controller;
import com.ag.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.Collection;
import java.util.Collections;
@RestController
@RequestMapping("/rest")
public class RestHandler {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/findAll")
public Collection<User> findAll(){
return restTemplate.getForObject("http://localhost:8080/user/findAll",Collection.class);
}
@GetMapping("/findById/{id}")
public User findById(@PathVariable("id") Integer id){
return restTemplate.getForObject("http://localhost:8080/user/findById/{id}",User.class,id);
}
@PostMapping("/save")
public void save(@RequestBody User user) {
restTemplate.postForObject("http://localhost:8080/user/save", user, Collection.class);
}
@PutMapping("/update")
public void update(@RequestBody User user){
restTemplate.put("http://localhost:8080/user/update",user);
}
@DeleteMapping("/deleteById/{id}")
public void deleteById(@PathVariable("id") Integer id){
restTemplate.delete("http://localhost:8080/user/deleteById/{id}",id);
}
}
4.服务消费者
1.创建 Module,pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
2.application.yml
server:
port: 8020
spring:
application:
name: consumer
eureka:
instance:
prefer-ip-address: true
client:
service-url:
defaultZone: http://localhost:8761/eureka/
3.配置启动类和RestTemplate
package com.ag;
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 Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
4.实体类
package com.ag.entity;
import lombok.Data;
@Data
public class Student {
private Integer id;
private String name;
}
5.StudentHandler
package com.ag.controller;
import com.ag.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 StudentHandler {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/findAll")
public Collection<Student> findAll(){
return restTemplate.getForObject("http://localhost:8010/provider/findAll", Collection.class);
}
@GetMapping("/findById/{id}")
public Student finById(@PathVariable("id") Integer id){
return restTemplate.getForObject("http://localhost:8010/provider/findById/{id}",Student.class,id);
}
@PostMapping("/save")
public void save(@RequestBody Student student){
restTemplate.postForObject("http://localhost:8010/provider/save",student,Student.class);
}
@PutMapping("/update")
public void update(@RequestBody Student student){
restTemplate.put("http://localhost:8010/provider/update",student);
}
@DeleteMapping("/deleteById/{id}")
public void deleteById(@PathVariable("id") Integer id){
restTemplate.delete("http://localhost:8010/provider/deleteById/{id}",id);
}
}
5.服务⽹关
API ⽹关可以对所有的 API 请求进⾏统⼀的管理维护,相当于为系统开放出⼀个统⼀的接⼝,所有的外部请求只需要统⼀访问这个外部⼊⼝即可,系统内部再通过 API ⽹关去映射不同的微服务。
对于开发者⽽⾔就不需要关注具体的微服务 URL,直接访问⽹关即可。
Spring Cloud Zuul
1.创建 Module,pom.xml
<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>
2.application.yml
server:
port: 8030
spring:
application:
name: gateway
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
zuul:
routes:
provider: /p/**
# 给provider服务起别名,
3.创建启动类
package com.ag;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@EnableAutoConfiguration
@EnableZuulProxy
public class gateWayApplicaation {
public static void main(String[] args) {
SpringApplication.run(gateWayApplicaation.class,args);
}
}
6.Ribbon 负载均衡
Spring Cloud 提供的⼀种负载均衡解决⽅案,Ribbon 是 Netflflix 发布的负载均衡器,Spring Cloud Ribbon。
Ribbon 的使⽤同样需要结合 Eureka Server
负载均衡算法:轮询、随机、加权轮询、加权随机
1.创建 Module,pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
2.application.yml
server:
port: 8040
spring:
application:
name: ribbon
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
3.创建启动类 和restTemplate @LoadBalanced配置负载均衡
package com.ag;
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();
}
}
4.创建handler
package com.ag.conteoller;
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;
@RestController
@RequestMapping("/ribbon")
public class RibbonHandler {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/index")
public String index(){
return restTemplate.getForObject("http://consumer/consumer/index",String.class);
}
}
5.在consumer的controller中配置
@Value("${server.port}")
private String port;
@GetMapping("/index")
public String index(){
return "consumer: "+port;
}
6.再建立一个启动类
启动一个启动类后,改端口为8021,然后启动另一个启动了
实现了负载均衡
7.Fiegn 声明式接⼝调⽤
1.什么是Feign
Netflflix,Feign 是⼀个提供模版的声明式 Web Service 客户端,使⽤ Feign 可以简化 Web Service 客户端的编写,开发者可以通过简单的接⼝和注解来调⽤ HTTP API。
Spring Cloud Feign:可插拔、基于注解、负载均衡、服务熔断
Feign 的英文表意为“假装,伪装,变形”, 是一个http请求调用的轻量级框架,可以以Java接口注解的方式调用Http请求,而不用像Java中通过封装HTTP请求报文的方式直接调用。Feign通过处理注解,将请求模板化,当实际调用的时候,传入参数,根据参数再应用到请求上,进而转化成真正的请求,这种请求相对而言比较直观
Feign 的特点:
- Feign 是⼀个声明式 Web Service 客户端
- ⽀持 Feign 注解、Spring MVC 注解
- Feign 基于 Ribbon 实现
- Feign 集成了 Hystrix
1.创建 Module,pom.xml
<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-openfeign</artifactId>
</dependency>
</dependencies>
2.application.yml
server:
port: 8050
spring:
application:
name: fiegn
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
3.启动类
package com.ag;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableFeignClients
@SpringBootApplication
public class fiegnApplication {
public static void main(String[] args) {
SpringApplication.run(fiegnApplication.class,args);
}
}
4.实体类
package com.ag.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private Integer id;
private String name;
}
5.FeignProviderClient 接⼝
package com.ag.fiegn;
import com.ag.entity.Student;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.Collection;
@FeignClient("provider") //写服务的名称(yml中配置的)
public interface FeignProviderClient {
@GetMapping("/provider/findAll")
public Collection<Student> findAll();
@GetMapping("/provider/findById/{id}")
public Student findById(@PathVariable("id") Integer id);
@PostMapping("/provider/save")
public void save(@RequestBody Student student);
@PutMapping("/provider/update")
public void update(@RequestBody Student student);
@DeleteMapping("/provider/deleteById/{id}")
public void deleteById(@PathVariable("id") Integer id);
}
6.handler
package com.ag.controller;
import com.ag.entity.Student;
import com.ag.fiegn.FeignProviderClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Collection;
@RestController
@RequestMapping("/fiegn")
public class fiegnHandler {
@Autowired
private FeignProviderClient feignProviderClient;
@GetMapping("/findAll")
public Collection<Student> findAll(){
return feignProviderClient.findAll();
}
@PostMapping("/save")
public void save(@RequestBody Student student){
feignProviderClient.save(student);
}
@PutMapping("/update")
public void update(@RequestBody Student student){
feignProviderClient.update(student);
}
@DeleteMapping("/deleteById/{id}")
public void deleteById(@PathVariable("id") Integer id){
feignProviderClient.deleteById(id);
}
}
8.Hystrix 容错监控机制
什么是微服务的容错机制
提前预设解决⽅案,系统进⾏⾃主调节,遇到问题及时处理
什么是 Hystrix
Netflflix
设计原则
- 服务隔离机制
- 服务降级机制
- 熔断机制
- 提供实时的监控和报警功能
- 提供实时的配置修改功能
1.创建 Module,pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>SpringCloud</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>hystrix</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<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-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
2.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'
3.创建启动类
package com.ag;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
@EnableCircuitBreaker // 开启熔断器
public class hystrixApplication {
public static void main(String[] args) {
SpringApplication.run(hystrixApplication.class,args);
}
}
4.实体类
package com.ag.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private Integer id;
private String name;
}
5.FeignProviderClient 接⼝
package com.ag.fiegn;
import com.ag.entity.Student;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.Collection;
@FeignClient("provider") //写服务的名称(yml中配置的)
public interface FeignProviderClient {
@GetMapping("/provider/findAll")
public Collection<Student> findAll();
@GetMapping("/provider/findById/{id}")
public Student findById(@PathVariable("id") Integer id);
@PostMapping("/provider/save")
public void save(@RequestBody Student student);
@PutMapping("/provider/update")
public void update(@RequestBody Student student);
@DeleteMapping("/provider/deleteById/{id}")
public void deleteById(@PathVariable("id") Integer id);
}
6.controller
package com.ag.controller;
import com.ag.entity.Student;
import com.ag.fiegn.FeignProviderClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Collection;
@RestController
@RequestMapping("/fiegn")
public class hystrixHandler {
@Autowired
private FeignProviderClient feignProviderClient;
@GetMapping("/findAll")
public Collection<Student> findAll(){
return feignProviderClient.findAll();
}
@PostMapping("/save")
public void save(@RequestBody Student student){
feignProviderClient.save(student);
}
@PutMapping("/update")
public void update(@RequestBody Student student){
feignProviderClient.update(student);
}
@DeleteMapping("/deleteById/{id}")
public void deleteById(@PathVariable("id") Integer id){
feignProviderClient.deleteById(id);
}
}
数据监控 URL:http://localhost:8060/actuator/hystrix.stream
7.添加可视化界⾯组件
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
8.启动类添加相应注解
package com.ag;
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);
}
}
可视化界⾯ URL:http://localhost:8060/hystrix
9.Spring Cloud Confifig 本地配置
我们可以将微服务的相关配置⽂件存储到本地⽂件中,然后让微服务来读取本地配置⽂件
就是把各个微服务的配置文件集中在一起,统一管理。
创建本地 Confifig Server
1.创建 Module nativeconfigserver,pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
</dependencies>
2.application.yml
server:
port: 8762
spring:
application:
name: nativeconfigserver
# 设置类型为本地
profiles:
active: native
# 设置检索路径
cloud:
config:
server:
native:
search-locations: classpath:/shared
3.在 resources 路径下创建 shared ⽂件夹,并在此路径下创建本地配置⽂件 confifigclient-dev.yml
server:
port: 8070
foo: foo version 1
4.创建启动类
package com.ag;
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);
}
}
创建客户端读取配置中⼼的配置⽂件。
1.创建 Module nativeconfigclient,pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
</dependencies>
2.bootstrap.yml
#这个是在配置中心的文件名,寻找 configclient-dev名称的配置文件
spring:
application:
name: configclient
profiles:
active: dev
# 这个是配置中心的路径
cloud:
config:
uri: http://localhost:8762
fail-fast: true
3.创建启动类
package com.ag;
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);
}
}
4.handler
package com.ag.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;
}
}
客户端成功读取到了配置中心的数据
10.Spring Cloud 服务跟踪
Zipkin 实现服务跟踪
什么是 Zipkin
- Zipkin Server
- Zipkin Client
Spring Cloud Sleuth 集成了 Zipkin
创建 Zipkin Server
1.创建 Module zipkinserver,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>
2.application.yml
server:
port: 9091
3.启动类
package com.ag;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import zipkin.server.internal.EnableZipkinServer;
@EnableZipkinServer
@SpringBootApplication
public class zipkinServerApplication {
public static void main(String[] args) {
SpringApplication.run(zipkinServerApplication.class,args);
}
}
创建 Zipkin Client
1、创建 Module zipkinclient,pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
</dependencies>
2.application.yml
server:
port: 8090
spring:
application:
name: zipkinclient
# 启用 服务跟踪的web客户端
sleuth:
web:
client:
enabled: true
#spring.sleuth.sampler.probability可以设置为小数,最大值为1.0,当设置为1.0时就是链路数据100%收集到zipkin-server,
# 当设置为0.1时,即10%概率收集链路数据
sampler:
probability: 1.0
# 关联server
zipkin:
base-url: http://localhost:9091/
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
3.创建启动类
package com.ag;
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);
}
}
4.handler
package com.ag.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;
}
}
依次启动注册中⼼、Zipkin Server、Zipkin Client
访问 http://localhost:9091/zipkin/
客户端发起 Zipkin Client 请求,点击 Find Traces,可以看到服务跟踪数据