单体应用存在的问题
- 随着业务的发展,开发变得越来越复杂
- 修改、新增某个功能,需要对整个系统进行测试、重新部署
- 一个模块出问题,很可能导致整个系统崩溃
- 多个开发团队同时对数据进行管理,容易产生安全漏洞
- 各个模块使用同一种技术进行开发,各个模块很难根据实际情况选择更合适的技术框架,局限性很大
- 模块内容过于复杂,耦合性太高
何为分布式、集群、服务治理
集群(运维层面):一台服务器无法负荷高并发的数据访问量,增加服务器的数量,来缓解压力,通俗的讲就是很多人干同一件事情(物理层面)
分布式(开发层面):将一个复杂的问题拆分成若干个简单的小问题,将一个大型的项目架构拆分成若干个微服务来协同完成。(软件设计层面),通俗的讲就是将一个庞大的工作拆分成若干个小步骤,分别由不同的人完成这些小步骤,最终将所有的结果进行整合实现大的需求。
服务治理:核心三部分:服务提供者、服务消费者、注册中心。
服务注册:在分布式系统架构中,每个微服务在启动时,将自己的信息存储在注册中心,叫做服务注册
**服务发现:**服务消费者从注册中心获取服务提供者的网络信息,通过该信息调用服务,叫做服务发现
Spring Cloud的服务治理使用Eureka来实现,Eureka是Netfilx开源的基于REST服务治理解决方案,Spring Cloud集成了Eureka,提供服务注册和服务发现的功能,可以和基于Spring Boot 搭建的微服务应用轻松地完成整合,开箱即用,Spring Cloud Eureka。
Spring Cloud Eureka
- Eureka Server:注册中心
- Eureka Client,所有要进行注册的微服务通过Eureka Client连接到Eureka Server,完成注册。
Eureka Server代码实现
- 创建父工程,pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.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>
<version>1.18.6</version>
<scope>provided</scope>
</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>
- 在父工程下创建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>
- 创建配置文件application.yml,添加Eureka Server相关配置。
#当前Eureka Server服务端口。
server:
port: 8761
eureka:
client:
#是否将当前的Eureka Server服务端作为客户进行注册
register-with-eureka: false
#是否获取其他Eureka Server 服务的数据
fetch-registry: false
service-url:
#注册中心的访问地址
defaltZone: http://localhost:8761/eureka/
- 创建启动类
package com.yl.llh;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
//声明该类是Spring Boot服务的入口
@SpringBootApplication
//声明该类是一个Eureka Server 微服务,提供服务注册和服务发现功能,即注册中心。
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class,args);
}
}
Eureka Client代码实现
- 创建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>
- 创建配置文件application.yml,添加Eureka Client相关配置
server:
port: 8010
spring:
application:
#当前服务注册在Eureka Server上的名称
name: provider
eureka:
client:
service-url:
#注册中心的访问地址
defaultZone: http://localhost:8761/eureka
instance:
#是否将当前服务的ip注册到Eureka Server
prefer-ip-address: true
- 创建启动类
package com.yl.llh;
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);
}
}
- 创建实体类
package com.yl.llh.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;
}
- 创建增删改查接口
package com.yl.llh.repository;
import com.yl.llh.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);
}
- 实现接口方法
package com.yl.llh.repository.impl;
import com.yl.llh.entity.Student;
import com.yl.llh.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.yl.llh.controller;
import com.yl.llh.entity.Student;
import com.yl.llh.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 "当前端口:"+this.port;
}
}
RestTemplate 的使用
- 什么是RestTemplate?
RestTemplate是Spring框架提供的基于REST的服务组件,底层是对HTTP请求及响应进行的封装,提供了很多访问REST服务的方法,可以简化代码开发。
-
如何使用RestTemplate?
1、创建maven工程,pom.xml。
2、创建实体类
package com.yl.llh.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.yl.llh.controller; import com.yl.llh.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、启动类
package com.yl.llh; 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(); } }
服务消费者consumer
-
创建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>
-
创建配置文件application.yml
server: port: 8020 spring: application: name: consumer eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ instance: prefer-ip-address: true
-
创建启动类
package com.yl.llh;
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.yl.llh.controller;
import com.yl.llh.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);
}
}
server:
port: 8761
euraka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaltZone: http://localhost:8761/eureka/
服务网关
Spring Cloud 集成了 Zuul 组件,实现服务网关
- 什么是Zuul?
Zuul是Netflix 提供的一个开源的API网关服务器,是客户端和网站后端所有请求的中间层,对外开放一个API,将所有请求导入统一的入口,屏蔽了服务端的具体实现逻辑,Zuul可以实现反向代理的功能,在网关内部实现动态路由、身份认证、IP过滤、数据监控等。
- 创建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>
- 创建配置文件application.yml
server:
port: 8030
spring:
application:
name: geteway
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
zuul:
routes:
provider: /p/**
- 创建启动类
package com.yl.llh;
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);
}
}
- Zuul自带了负载均衡功能,修改provider的代码。
Ribbon 负载均衡
- 什么是Ribbon?
Soring Cloud Ribbon 是一个负载均衡解决方案,Ribbon是Netflix发布的负载均衡器,Spring Cloud Ribbon是基于NetFlix Ribbon 实现的,是一个用于对HTTP请求进行控制的负载均衡客户端。
在注册中心对RIbbon进行注册之后,Ribbon就可以基于某种负载均衡算法,如轮询、随机、加权轮询、加权随机等自动帮助服务消费者调用接口,开发者也可以根据具体需求自定义Ribbon负载均衡算法,实际开发中,Spring Cloud Ribbon需要结合Spring Cloud Eureka来使用,Eureka Server提供所有可以调用的服务提供者列表,Ribbon基于特定的负载均衡算法从这些服务提供者中选择要调用的具体实例。
- 创建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>
- 创建配置文件,application.yml
server:
port: 8040
spring:
application:
name: ribbon
eureka:
client:
service-url:
defaultZone: http://local:8761/eureka/
instance:
prefer-ip-address: true
- 创建启动类
package com.yl.llh;
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();
}
}
- Handler
package com.yl.llh.controller;
import com.yl.llh.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一样,Feign也是有Netfilx提供的,Feign是一个声明式、模板化的Web Service客户端,它简化了开发者编写Web服务客户端的操作,开发者可以通过简单的接口和注解来调用HTTP API,Spring Cloud Feign,它整合了Ribbon和Hystrix,具有可插拔、基于注解、负载均衡、服务熔断等一系列便捷功能。
相比较于Ribbon+RestTemplate的方式,Feign大大简化了代码的开发,Feign支持多中注解,包括Feign注解、JAX-RS注解、Spring MVC注解,Spring Cloud对Feign进行了优化,整合了Ribon和Eureka,从而让Feign的使用更加方便。
- Ribbon和Feign的区别
Ribbon是一个通用的HTTP客户端工具,Feign是基于Ribbon实现的。
- Feign的特点
1、Feign是一个声明式的Web Service 客户端
2、支持Feign注解、Spring MVC注解、JAX-RS注解
3、Feign基于Ribbon实现,使用起来更加简单。
4、Feign集成了Hystrix,具备服务熔断的功能
-
什么是服务熔断?
在互联网系统中,当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。这种牺牲局部,保全整体的措施就叫做熔断。
-
创建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>
- 创建配置文件,application.yml
server:
port: 8050
spring:
application:
name: feign
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
- 创建启动类
package com.yl.llh;
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);
}
}
- 创建声明式接口
package com.yl.llh.feign;
import com.yl.llh.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.yl.llh.controller;
import com.yl.llh.entity.Student;
import com.yl.llh.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();
}
}
- 服务熔断,application.yml添加熔断机制。
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
- 创建FeignProviderClient实现类FeignProviderClientFallBackFactory,定义容错处理逻辑,通过
@Component
注解将FeignProviderClientFallBackFactory实例注入IOC中
package com.yl.llh.feign.fallback;
import com.yl.llh.entity.Student;
import com.yl.llh.feign.FeignProviderClient;
import org.springframework.stereotype.Component;
import java.util.Collection;
@Component
public class FeignProviderClientFallBackFactory implements FeignProviderClient {
@Override
public Collection<Student> findAll() {
return null;
}
@Override
public String index() {
return "服务器维护中......";
}
}
- 在FeignProvidrerClient定义处通过
@FeignClient
的fallback的属性设置映射。
package com.yl.llh.feign;
import com.yl.llh.entity.Student;
import com.yl.llh.feign.impl.FeignError;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.Collection;
//正确执行provider,错误执行FeignError.class
@FeignClient(value = "provider",fallback = FeignProviderClientFallBackFactory.class)
public interface FeignProviderClient {
@GetMapping("/student/findAll")
public Collection<Student> findAll();
@GetMapping("/student/index")
public String index();
}
Hystrix 容错机制
在不改变各个微服务调用关系的前提下,针对错误情况进行预先处理。
- 设计原则
1、服务隔离机制:指防止某个服务提供者出现问题而影响到整个系统的运行
2、服务降级机制:指服务出现故障时向服务消费者返回fallback的降级处理
3、熔断机制:当服务消费者请求失败率达到某一个特定的数值的时候会迅速启动熔断机制,并对错误进行修复
4、提供实时的监控和报警功能
5、提供实时的配置修改功能
Hystrix数据监控需要结合Spring Boot Actuator 来使用,Actuator提供了对服务的健康监控、数据统计,可以通过Hystrix-stream节点获取监控的请求数据,提供了可视化的监控界面。
- 创建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>
- 创建配置文件,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'
- 创建启动类
package com.yl.llh;
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);
}
}
- Handler
package com.yl.llh.contorller;
import com.yl.llh.entity.Student;
import com.yl.llh.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();
}
}
- 启动成功之后,访问
http://localhost:8060/actuator/hystrix.stream
可以监控到请求数据 - 访问
http://localhost:8060/hystrix
,可以看到可视化的监控界面,输入要监控的地址节点即可看到该节点的可视化数据监控。
Spring Cloud 配置中心
Spring Cloud Config,通过服务端可以为多个客户端提供配置服务。Spring Cloud Config可以将配置文件存储在本地,也可以将配置文件存储在Git仓库,创建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>
- 创建application.yml
server:
port: 8760
spring:
application:
name: nativeconfigserver
#配置文件的获取方式
profiles:
#从本地获取
active: native
#本地配置文件存放的路径
cloud:
config:
server:
native:
search-locations: classpath:/shared
- resources路径下创建shared文件夹,并在此路径下创建configcliebt-dev.yml.
server:
port: 8070
foo: foo version 1.0
- 创建启动类
package com.yl.llh;
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);
}
}
创建客户端,来读取本地配置中心的配置文件
- 创建Maven工程,pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
</dependencies>
- 创建配置文件 bootstrap.yml,配置读取本地配置中心的相关信息
spring:
application:
name: configclient
profiles:
active: dev
cloud:
config:
#配置本地Config Server 的访问路径
uri: http://localhost:8762
#设置客户端优先判断Config Server 获取是否正常。
fail-fast: true
说明
通过spring.application.name
结合spring.profiles.active
拼接目标配置文件名,configclient-dev.yml,去Config Server 中查找该文件。
- 创建启动类
package com.yl.llh;
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.yl.llh.controller;
import org.springframework.beans.factory.annotation.Value;
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 post;
@Value("${foo}")
private String foo;
@GetMapping("/index")
public String index(){
return this.post+"-"+this.foo;
}
}
Spring Cloud Config 远程配置
- 创建配置文件,上传至远程仓库
server:
port: 8070
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
spring:
spplication:
name: configclient
- 创建ConfigServer,新建Maven工程,pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
</dependencies>
- 创建配置文件 application.yml
server:
port: 8888
spring:
application:
name: configserver
cloud:
config:
server:
git:
uri: git地址
search-paths: config
username: 用户名
password: 密码
label: master
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
- 创建启动类
package com.yl.llh;
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);
}
}
创建config Client
- 创建Maven工程,pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
</dependencies>
- 创建bootstrap.yml
Spring:
cloud:
config:
#当前服务注册在Eureka Server上的名称,与远程仓库配置文件名对应
name: configclient
#Git Repository 的分支。
label: master
discovery:
#是否开启Config服务发现支持。
enabled: true
#配置中心在Eureka Server 上注册的名称
service-id: configserver
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
- 创建启动类
package com.yl.llh;
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.yl.llh.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;
}
}
服务跟踪
- Spring Cloud Zipkin是什么
Zipkin是一个可以采集并且跟踪分布式系统中请求数据的组件,让开发者可以更加直观的监控到请求在各个微服务所耗费的时间等,Zipkin:Zipken Server、Zipkin Client。
创建Zipkin服务端,ZipkinServer
- 创建Maevn工程,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>
- 创建配置文件,application.yml
server:
port: 9090
- 创建启动类
package com.yl.llh;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import zipkin.server.internal.EnableZipkinServer;
@SpringBootApplication
//声明启动ZipkinServer
@EnableZipkinServer
public class ZipkinApplication {
public static void main(String[] args) {
SpringApplication.run(ZipkinApplication.class,args);
}
}
创建Zipkin客户端,ZipKinClient
- 创建Maven工程。pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
</dependencies>
- 创建配置文件application.yml
server:
port: 8090
spring:
application:
name: zipkinclient
sleuth:
web:
client:
#设置开启请求跟踪
enabled: true
sampler:
#设置采样比例,默认1.0
probability: 1.0
zipkin:
#Zipkin Server 地址
base-url: http://localhost:9090/
eureka:
client:
server-url:
dafaultZone: http://localhost:8761/eureka/
-
创建启动类
package com.yl.llh; 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); } }
-
Hander
package com.yl.llh.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;
}
}