文章目录
- Spring Cloud NetFlix
- 1 介绍
- 2 Eureka(服务注册与发现)
- 2.1 介绍
- 2.2 服务注册与发现示例
- 2.2.1 Eureka Server:springcloud-eureka
- 2.2.2 Eureka Client:springcloud-provider
- 2.2.3 Eureka Client:springcloud-consumer
- 2.3 Eureka主从
- 3 Ribbon(负载均衡)
- 3.1 介绍
- 3.2 负载均衡策略
- 3.3 负载均衡示例
- 3.3.1 Eureka Server:springcloud-eureka
- 3.3.2 Eureka Client:springcloud-provider1
- 3.3.3 Eureka Client:springcloud-provider2
- 3.3.4 Eureka Client:springcloud-consumer
- 4 Hystrix(熔断器)
- 4.1 介绍
- 4.2 熔断示例
- 4.2.1 Eureka Server:springcloud-eureka
- 4.2.2 Eureka Client:springcloud-provider
- 4.2.3 Eureka Client:springcloud-consumer
- 4.2.2 Eureka Client:springcloud-dashboard
- 5 Feign(声明式服务调用)
- 5.1 介绍
- 5.2 示例
- 5.2.1 Eureka Server:springcloud-eureka
- 5.2.2 Eureka Client:springcloud-feign-provider
- 5.2.3 Eureka Client:springcloud-feign-consumer
- 6 Zuul(API网关)
- 6.1 介绍
- 6.2 示例
- 6.2.1 Eureka Server:springcloud-eureka
- 6.2.2 Eureka Client:springcloud-zuul-provider
- 6.2.3 Eureka Client:springcloud-zuul-gateway
- 6.2.4 Eureka Client:springcloud-zuul-consumer
Spring Cloud NetFlix
1 介绍
Spring Cloud是一套用于构建分布式系统的框架,它基于Spring Boot提供了一系列工具和库,用于快速开发具有弹性、可伸缩、分布式特性的微服务应用。Spring Cloud提供了众多功能,包括服务注册与发现、配置中心、负载均衡、断路器、网关等,帮助开发者轻松构建和管理微服务架构。
以下是一些Spring Cloud的核心组件和功能:
-
Eureka(服务注册与发现): Eureka是Spring Cloud的服务注册与发现组件,允许服务注册和发现。服务提供者在启动时向Eureka注册自己,而服务消费者可以从Eureka中获取注册的服务列表,从而实现服务的动态发现。
-
Ribbon(负载均衡): Ribbon是一个客户端负载均衡器,可以与Eureka等服务注册中心集成,实现对微服务的负载均衡。
-
Feign(声明式服务调用): Feign是一个声明式的Web服务客户端,可以更轻松地实现服务之间的调用。通过使用注解,开发者可以定义接口,并在接口中使用注解来描述服务的调用方式,而Feign会根据这些注解自动生成具体的实现。
-
Hystrix(熔断器): Hystrix是一个用于处理延迟和容错的库,它提供了熔断、隔离、Fallback等功能,保护分布式系统在高负载和故障情况下的稳定性。
-
Zuul(API网关): Zuul是一个API网关服务,用于提供统一的入口和出口,实现路由、负载均衡、认证、监控等功能。
-
Config(配置中心): Config组件用于实现分布式系统中的外部化配置,可以将配置信息存储在远程仓库中,实现配置的集中管理。
-
Bus(消息总线): Spring Cloud Bus通过消息代理将分布式系统的节点连接在一起,支持动态刷新配置、传播状态变化等功能。
-
Spring Cloud Stream(消息驱动): Spring Cloud Stream是一个用于构建消息驱动的微服务的框架,提供了简化消息通信的抽象。
这些组件和功能使得开发者能够更方便地构建和管理微服务架构,提供了一系列解决方案,用于应对分布式系统中的常见问题。Spring Cloud的设计理念是构建弹性、可伸缩、分布式的微服务架构,使得开发者能够更专注于业务逻辑的实现而不用过多关注底层的分布式系统细节。
2 Eureka(服务注册与发现)
2.1 介绍
Eureka是Spring Cloud中的一个服务注册与发现组件,它的主要功能是帮助微服务架构中的服务实现自动注册与发现。通过Eureka,服务提供者可以向注册中心注册自己的服务,并且服务消费者可以从注册中心获取服务提供者的信息,实现动态的服务发现。
以下是Eureka的一些主要特点和概念:
-
服务注册: 微服务在启动时会向Eureka Server注册自己的信息,包括服务名、IP地址、端口等。
-
服务发现: 微服务在运行时可以通过向Eureka Server发送请求来获取已注册的服务列表。服务消费者可以从注册中心中获取服务提供者的信息,从而实现动态的服务发现。
-
服务治理: Eureka通过定期发送心跳检测服务的可用性,并在一段时间内没有收到心跳时将服务标记为不可用。这有助于实现服务的自动下线和服务的高可用性。
-
区域和可用性区分: Eureka支持将服务注册到不同的区域(Region)和可用性区域(Availability Zone)。这对于构建分布式系统的多区域部署提供了支持。
-
自我保护机制: Eureka具有自我保护机制,当Eureka Server节点在一段时间内没有收到某个服务的心跳时,它会保护该服务,不会立即剔除,防止因为网络等原因造成的误剔除。
-
Eureka Client: Eureka提供了Eureka Client库,使得微服务能够方便地与Eureka Server交互,实现服务注册和发现。
在Spring Cloud中使用Eureka通常涉及以下几个关键配置:
Eureka Server 配置:
server:port: 8761spring:application:name: service-nameeureka:client:register-with-eureka: false #告知注册中心 你不能向你自己注册fetch-registry: false #主要作用是维护服务,不是检索服务service-url:defaultZone: http://localhost:8761/eureka/
Eureka Client 配置:
server:port: 8762spring:application:name: service-nameeureka:client:service-url:defaultZone: http://localhost:8761/eureka/ #注册中心的地址
2.2 服务注册与发现示例
2.2.1 Eureka Server:springcloud-eureka
添加依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
配置 application.properties
server.port=9100
spring.application.name=eureka-server
#设置注册中心
eureka.instance.hostname=localhost
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
#注册中心的地址
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka
启动类:
@SpringBootApplication
@EnableEurekaServer //启动eureka
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
启动应用,访问http://localhost:9100,将看到Eureka Server的控制台页面:
2.2.2 Eureka Client:springcloud-provider
添加依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
配置 application.properties
server.port=8083
spring.application.name=server-provider
eureka.client.service-url.defaultZone=http://localhost:9100/eureka
启动类
@SpringBootApplication
@EnableEurekaClient
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
编写TestController
@RestController
public class TestController {@RequestMapping("/test")public String test(){return "使用了Eureka注册中心的服务提供者!";}
}
启动应用,刷新http://localhost:9100,可以看到Eureka Server的控制台页面:
此时,已经将服务注册到注册中心。
2.2.3 Eureka Client:springcloud-consumer
添加依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
配置 application.properties
server.port=8084
spring.application.name=server-consumer
eureka.client.service-url.defaultZone=http://localhost:9100/eureka
启动类
@SpringBootApplication
@EnableEurekaClient
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
编写 RestTemplateConfig
@Configuration
public class RestTemplateConfig {/*** LoadBalanced 标记 restTemplate使用 ribbon 的 负载均衡策略访问服务的提供者* 使用了 Eureka注册中心后 restTemplate 对象上方必须添加该注解*/@Bean@LoadBalancedpublic RestTemplate restTemplate(){return new RestTemplate();}
}
编写 TestController
@RestController
public class TestController {@Autowiredprivate RestTemplate restTemplate;@RequestMapping("/test")public String test(){ResponseEntity<String> result = restTemplate.getForEntity("http://SERVER-PROVIDER/test", String.class);return result.getBody();}
}
启动应用,刷新http://localhost:9100,可以看到Eureka Server的控制台页面:
再访问 http://localhost:8084/test,得到结果:
这说明,consumer 通过注册中心获取服务提供者的信息。
2.3 Eureka主从
在Eureka中,没有官方定义的“主从”概念,因为Eureka本身是为了构建高可用的服务注册和发现系统而设计的。Eureka Server之间通过互相注册为对方的客户端来实现高可用性。每个Eureka Server都包含了完整的服务实例信息,因此可以独立运行。
如果想要搭建一个具备高可用性的Eureka集群,可以简单地在多个地点启动Eureka Server实例,并将它们互相注册为对方的客户端。这样,每个Eureka Server都包含了完整的服务实例信息,客户端在向任何一个Eureka Server注册服务时,这个信息会被同步到集群中的其他Eureka Server。
以下是一个简单的示例,演示了如何在两个Eureka Server之间实现互相注册:
在 C:\Windows\System32\drivers\etc\hosts 文件中进行ip地址映射,修改内容如下 :
127.0.0.1 eureka9100
127.0.0.1 eureka9200
-
Eureka Server1配置:
server.port=9100spring.application.name=eureka9100eureka.instance.hostname=localhosteureka.client.register-with-eureka=falseeureka.client.fetch-registry=falseeureka.client.service-url.defaultZone=http://eureka9200:9200/eureka
-
Eureka Server2配置:
server.port=9200spring.application.name=eureka9200eureka.instance.hostname=localhosteureka.client.register-with-eureka=falseeureka.client.fetch-registry=falseeureka.client.service-url.defaultZone=http://eureka9100:9100/eureka
在这个示例中,两个Eureka Server相互注册,形成一个简单的高可用集群。可以进一步扩展集群规模,添加更多的Eureka Server实例,以提高系统的可用性。
注意:Eureka本身并没有“主从”之分,所有的Eureka Server都是对等的,它们之间通过相互注册来实现高可用性。
3 Ribbon(负载均衡)
3.1 介绍
Ribbon是Netflix开源的一个基于HTTP和TCP客户端的负载均衡器,它主要用于在微服务架构中进行客户端的负载均衡。在Spring Cloud中,Ribbon通常被集成为一个客户端负载均衡器,用于在服务调用时选择合适的目标服务实例。以下是Ribbon的一些关键特点和介绍:
-
负载均衡算法: Ribbon支持多种负载均衡算法,包括常见的轮询(Round Robin)、随机(Random)、加权轮询、加权随机等。这些算法可以根据实际需求进行配置。
-
服务实例选择: Ribbon通过与服务注册中心(如Eureka)集成,动态地获取可用的服务实例列表,并根据负载均衡算法选择目标服务实例。这样,即使服务实例的数量发生变化,Ribbon也能够自动适应。
-
超时和重试: Ribbon具备超时和重试机制,可以在调用服务时设置超时时间,并在发生错误时进行重试。这有助于提高系统的可靠性和容错能力。
-
自定义规则: 用户可以通过自定义的方式指定服务实例的选择规则,以满足特定的业务需求。例如,可以根据服务实例的元数据、性能指标等进行智能的服务选择。
-
集成Spring Cloud: 在Spring Cloud中,Ribbon与Eureka、Feign等组件无缝集成,使得微服务架构中的服务间调用更加方便。通过在Feign客户端中使用
@LoadBalanced
注解,可以让Feign利用Ribbon进行负载均衡。 -
动态属性配置: Ribbon支持动态属性配置,可以通过配置中心(如Spring Cloud Config)实时更新负载均衡的相关配置,而不需要重新启动服务。
-
可扩展性: Ribbon是一个可扩展的负载均衡框架,可以通过实现特定的接口来定制负载均衡策略,以适应不同场景下的需求。
3.2 负载均衡策略
在Spring Cloud中使用Ribbon作为客户端负载均衡器时,可以通过配置来指定负载均衡的策略。Ribbon支持多种负载均衡策略,常见的包括:
-
RoundRobin(默认): 轮询策略,依次将请求分发到各个服务实例上。
-
RandomRule: 随机策略,随机选择一个可用的服务实例进行请求。
-
WeightedResponseTimeRule: 响应时间加权策略,根据服务实例的响应时间进行加权,响应时间越短的服务实例被选择的概率越大。
-
RetryRule: 具备重试机制的策略,当请求失败时,会进行重试。
-
BestAvailableRule: 选择一个并发请求最小的实例,适用于请求量比较大的场景。
-
ZoneAvoidanceRule: 综合判断服务节点所在的区域的性能和服务节点的可用性,来选择哪个服务 。
-
AvailabilityFilteringRule: 先过滤掉由于多次访问故障的服务,以及并发访问超过阈值的服务,然后对剩下的服务进行轮询访问策略。
3.3 负载均衡示例
3.3.1 Eureka Server:springcloud-eureka
添加依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
配置 application.properties
server.port=9100
spring.application.name=eureka-server
#设置注册中心
eureka.instance.hostname=localhost
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
#注册中心的地址
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka
启动类:
@SpringBootApplication
@EnableEurekaServer //启动eureka
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
3.3.2 Eureka Client:springcloud-provider1
添加依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
配置 application.properties
server.port=8084
spring.application.name=04-springcloud-provider
eureka.client.service-url.defaultZone=http://localhost:9100/eureka
启动类
@SpringBootApplication
@EnableEurekaClient
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
编写TestController
@RestController
public class TestController {@RequestMapping("/test")public String test(){return "使用了Eureka注册中心的8084服务提供者!";}
}
3.3.3 Eureka Client:springcloud-provider2
添加依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
配置 application.properties
server.port=8085
spring.application.name=04-springcloud-provider
eureka.client.service-url.defaultZone=http://localhost:9100/eureka
启动类
@SpringBootApplication
@EnableEurekaClient
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
编写TestController
@RestController
public class TestController {@RequestMapping("/test")public String test(){return "使用了Eureka注册中心的8085服务提供者!";}
}
3.3.4 Eureka Client:springcloud-consumer
添加依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
配置 application.properties
server.port=8086
spring.application.name=server-consumer
eureka.client.service-url.defaultZone=http://localhost:9100/eureka
启动类
@SpringBootApplication
@EnableEurekaClient
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
编写 RestTemplateConfig
@Configuration
public class RestTemplateConfig {/*** LoadBalanced 标记 restTemplate使用 ribbon 的 负载均衡策略访问服务的提供者* 使用了 Eureka注册中心后 restTemplate 对象上方必须添加该注解*/@Bean@LoadBalancedpublic RestTemplate restTemplate(){return new RestTemplate();}/*负载均衡策略*/@Beanpublic IRule iRule(){return new RoundRobinRule();//轮询访问
// return new RandomRule();//随机访问}
}
编写 TestController
@RestController
public class TestController {@Autowiredprivate RestTemplate restTemplate;@RequestMapping("/test")public String test(){ResponseEntity<String> result = restTemplate.getForEntity("http://04-springcloud-provider/test", String.class);return result.getBody();}
}
启动4个应用,网址栏输入http://localhost:9100,可以看到Eureka Server的控制台页面:
由于使用的是RoundRobin轮询策略,依次将请求分发到各个服务实例上。
访问http://localhost:8086/test,得到结果:
刷新http://localhost:8086/test,得到结果:
4 Hystrix(熔断器)
4.1 介绍
Hystrix是Netflix开源的一个用于处理分布式系统的容错组件,它主要用于防止服务雪崩,提高系统的稳定性。在微服务架构中,服务之间的依赖关系复杂,一个服务的不可用可能会导致整个系统的不可用。Hystrix通过引入熔断器模式、隔离、Fallback等机制,提供了一种弹性和容错的解决方案。
以下是Hystrix的一些关键特点和概念:
-
熔断器模式: Hystrix通过引入熔断器模式,可以在服务调用失败时快速返回一个Fallback响应,而不是等待调用超时。当服务连续失败达到一定阈值时,Hystrix会启动熔断器,暂时阻断对失败服务的调用,避免对系统的进一步影响。
-
服务隔离: Hystrix通过线程池隔离和信号量隔离等方式,将不同的服务调用隔离开来,防止一个服务的问题影响到其他服务。这提高了系统的可用性,防止服务之间的故障传播。
-
超时和降级: Hystrix支持设置服务调用的超时时间,当调用超时时可以立即返回Fallback响应。同时,可以定义Fallback逻辑,即在主逻辑失败时执行备用逻辑,保障系统在某个服务不可用时仍能提供有限的功能。
-
请求缓存: Hystrix支持对相同请求的结果进行缓存,避免重复执行相同的操作,提高系统的性能。
-
实时监控和熔断器状态: Hystrix提供了实时的监控面板,可以查看熔断器的状态、请求的成功与失败情况、延迟分布等信息。通过这些监控数据,可以及时发现和解决系统中的问题。
-
Fallback策略: Hystrix允许为每个服务定义特定的Fallback策略,以应对不同服务的故障情况。Fallback逻辑通常是一些简化的、无依赖的操作,确保即使主逻辑失败,系统仍能提供基本的服务。
在Spring Cloud中,Hystrix通常与Feign、Ribbon等组件一起使用,以提供更可靠的微服务调用。通过在Feign客户端中添加@HystrixCommand
注解,可以将熔断逻辑嵌入到服务调用中。
4.2 熔断示例
4.2.1 Eureka Server:springcloud-eureka
添加依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
配置 application.properties
server.port=8761spring.application.name=eureka-server#设置注册中心
eureka.instance.hostname=localhost
#告知注册中心 你不能向你自己注册
eureka.client.register-with-eureka=false
#你的主要作用是维护服务 ,不是检索服务
eureka.client.fetch-registry=false
#注册中心的地址
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka
启动类:
@SpringBootApplication
@EnableEurekaServer //启动eureka
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
4.2.2 Eureka Client:springcloud-provider
添加依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
配置 application.properties
server.port=8083spring.application.name=providereureka.client.service-url.defaultZone=http://localhost:8761/eureka
启动类
@SpringBootApplication
@EnableEurekaClient
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
编写TestController
@RestController
public class TestController {@RequestMapping("/test")public String test(){int i = 1/0;return "使用了断路器的...";}@RequestMapping("/test02")public String test02(){try {Thread.sleep(1000000);} catch (InterruptedException e) {e.printStackTrace();}return "使用了熔断机制的...";}
}
4.2.3 Eureka Client:springcloud-consumer
添加依赖
<!--豪猪依赖-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency><!--仪表盘-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency><!-- 开启健康检查-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId>
</dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
配置 application.properties
server.port=8084spring.application.name=consumereureka.client.service-url.defaultZone=http://localhost:8761/eurekamanagement.endpoints.web.exposure.include=hystrix.stream
启动类
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker //启动熔断机制
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}}
编写 RestTemplateConfig
@Configuration
public class RestTemplateConfig {/*** LoadBalanced 标记 restTemplate使用 ribbon 的 负载均衡策略访问服务的提供者* 使用了 Eureka注册中心后 restTemplate 对象上方必须添加该注解*/@Bean@LoadBalancedpublic RestTemplate restTemplate(){return new RestTemplate();}
}
编写 MyHystrixCommand
public class MyHystrixCommand extends HystrixCommand<String> {private RestTemplate restTemplate;private String url;public MyHystrixCommand(Setter setter, RestTemplate restTemplate, String url) {super(setter);this.restTemplate = restTemplate;this.url = url;}@Overrideprotected String run() throws Exception {return restTemplate.getForObject(url,String.class);}@Overrideprotected String getFallback() {//需要在控制器中定义一个叫error的方法return "error";}
}
编写 TestController
@RestController
public class TestController {@Autowiredprivate RestTemplate restTemplate;@HystrixCommand(fallbackMethod = "error")@RequestMapping("/test")public String test(){ResponseEntity<String> result = restTemplate.getForEntity("http://provider/test", String.class);String body = result.getBody();return "使用了Hystrix的服务消费者:" + body;}public String error(Throwable throwable){System.out.println(throwable.getMessage());System.out.println(throwable.getClass());return "服务熔断了......";}//标识一个方法需要由Hystrix进行保护,指定了一个回调方法 error ,设置了超时时间为2000毫秒@HystrixCommand(fallbackMethod = "error",commandProperties = {@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "2000")})@RequestMapping("/test02")public String test02(){ResponseEntity<String> result = restTemplate.getForEntity("http://provider/test02", String.class);String body = result.getBody();return "使用了Hystrix的服务消费者:" + body;}
}
4.2.2 Eureka Client:springcloud-dashboard
添加依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-netflix-hystrix-dashboard</artifactId>
</dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
配置 application.properties
server.port=2001#用于配置 Hystrix Dashboard 允许代理的流(stream)的地址列表。
hystrix.dashboard.proxy-stream-allow-list=localhost#默认注册中心端口号就是8761
启动类
@SpringBootApplication
@EnableHystrixDashboard //启用Hystrix dashboard豪猪可视化监控中心
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
启动4个应用,网址栏输入http://localhost:8761,可以看到Eureka Server的控制台页面:
浏览器输入http://localhost:8084/actuator/hystrix.stream,可以看到页面:
浏览器输入http://localhost:2001/hystrix,可以看到页面:
新建页面后输入http://localhost:8084/test,由于java.lang.ArithmeticException: / by zero异常,发生熔断:
此时,http://localhost:8084/actuator/hystrix.stream页面发生变化
在豪猪页面输入http://localhost:8084/actuator/hystrix.stream:
点击按钮后可以看到仪表盘:
新建页面后输入http://localhost:8084/test02,由于线程睡眠超过2秒,发生熔断:
查看仪表盘:
5 Feign(声明式服务调用)
5.1 介绍
Feign 是一个声明式的、模板化的 HTTP 客户端,它是 Spring Cloud 生态系统中的一部分,用于简化服务间的 HTTP 调用。Feign 的设计目标是使 HTTP 客户端的编写变得更加简单和直观。下面是 Feign 的一些主要特点和用法:
-
声明式 API 定义: Feign 允许你使用注解方式定义 HTTP 客户端的接口。通过简单的注解,你可以指定服务端的 URL、HTTP 方法、请求参数等信息,而不需要手动构建 HTTP 请求。
@FeignClient(name = "example", url = "http://example.com") public interface MyFeignClient {@RequestMapping("/api/resource")String getResource(); }
-
集成 Ribbon: Feign 集成了 Ribbon 负载均衡器,因此它可以与服务发现(如 Eureka)一起使用,实现对多个服务实例的负载均衡。
-
支持多种编码器和解码器: Feign 支持多种编码器和解码器,包括 JSON、XML 等,可以根据需求选择合适的序列化方式。
-
集成 Hystrix: Feign 可以集成 Hystrix,实现对服务调用的容错和熔断功能。通过
@HystrixCommand
注解,可以定义服务调用失败时的降级逻辑。@FeignClient(name = "example", url = "http://example.com", fallback = MyFallback.class) public interface MyFeignClient {@RequestMapping("/api/resource")@HystrixCommand(fallbackMethod = "fallbackMethod")String getResource(); }
Feign 的目标是简化服务调用的过程,让开发者可以更专注于业务逻辑而不是底层的 HTTP 请求。在 Spring Cloud 中,Feign通常与服务发现、负载均衡、断路器等组件一起使用,为微服务架构提供了便捷的服务间通信方式。
5.2 示例
5.2.1 Eureka Server:springcloud-eureka
添加依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
配置 application.properties
server.port=8761spring.application.name=eureka-server#设置注册中心
eureka.instance.hostname=localhost
#告知注册中心 你不能向你自己注册
eureka.client.register-with-eureka=false
#你的主要作用是维护服务 ,不是检索服务
eureka.client.fetch-registry=false
#注册中心的地址
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka
启动类:
@SpringBootApplication
@EnableEurekaServer //启动eureka
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
5.2.2 Eureka Client:springcloud-feign-provider
添加依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
配置 application.properties
server.port=8083spring.application.name=providereureka.client.service-url.defaultZone=http://localhost:8761/eureka
启动类
@SpringBootApplication
@EnableEurekaClient
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
编写TestController
@RestController
public class TestController {@RequestMapping("/test")public String test(){System.out.println(1/0);return "使用了feign的服务提供者";}
}
5.2.3 Eureka Client:springcloud-feign-consumer
添加依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
配置 application.properties
# 应用服务 WEB 访问端口
server.port=8084
spring.application.name=05-springcloud-feign-consumer
eureka.client.service-url.defaultZone=http://localhost:8761/eureka# 启用 Feign 的 Hystrix 支持
feign.hystrix.enabled=true
启动类
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients //激活 feign远程调用
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
编写User实体类
public class User {private String name;private Integer age;public User() {}public User(String name, Integer age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}
}
编写MyCallBackFactory
@Component
public class MyCallBackFactory implements FallbackFactory<TestService> {@Overridepublic TestService create(Throwable throwable) {return new TestService() {@Overridepublic String test() {return "使用了熔断器的 feign "+throwable.getMessage();}@Overridepublic String test01(String name, Integer age) {return name+age;}@Overridepublic User testUser() {return null;}};}
}
编写TestService
@FeignClient(name = "05-springcloud-feign-provider",fallbackFactory = MyCallBackFactory.class)
public interface TestService {@RequestMapping("/test")public String test();@RequestMapping("/test01")public String test01(@RequestParam("name") String name,@RequestParam("age") Integer age);@RequestMapping("/testUser")public User testUser();
}
编写TestController
@RestController
public class TestController {@Autowiredprivate TestService testService;@RequestMapping("/test")public String test(){/*RestTemplate restTemplate = new RestTemplate();restTemplate.getForEntity("http://provider/test",String.class);*/String body = testService.test01("kong",18);//return "使用feign的消费者的...["+body+"]";}
}
启动三个服务,访问http://localhost:8084/test01,远程调用了提供者的服务:
访问http://localhost:8084/test,由于by zero出现异常,发生熔断:
6 Zuul(API网关)
6.1 介绍
Zuul 是 Netflix 提供的一个基于 JVM 的边缘服务网关,它在微服务架构中扮演着 API 网关的角色,用于处理请求的路由、负载均衡、过滤、认证等一系列边缘服务功能。以下是 Zuul 的一些主要特点和功能:
-
路由(Routing): Zuul 可以根据请求的路径和规则将请求路由到不同的后端服务。这使得微服务架构中的多个服务可以通过一个统一的入口点提供服务。
-
负载均衡(Load Balancing): Zuul 集成了 Ribbon 负载均衡器,可以将请求平均分发到多个相同的后端服务实例上,以提高系统的可伸缩性和可用性。
-
过滤器(Filter): Zuul 使用过滤器来执行各种任务,例如身份验证、授权、日志记录等。开发者可以自定义过滤器来处理请求和响应,实现定制化的功能。
-
服务发现与注册: Zuul 可以与服务注册与发现中心(如 Eureka、Consul)集成,自动发现可用的服务实例,并将请求路由到它们之间。
-
动态路由: Zuul 支持动态路由配置,可以根据需要实时更新路由规则,而无需重启 Zuul 服务。
-
错误处理: Zuul 提供了对错误的处理机制,包括定制错误页面、错误重试等,以提高系统的稳定性。
-
监控与度量: Zuul 支持集成监控和度量工具,例如 Netflix 的 Hystrix、Spring Cloud Sleuth 等,以便对路由和服务调用进行监控和追踪。
-
安全性: Zuul 可以通过集成安全性解决方案来保护服务,例如 OAuth2、JWT 等。
6.2 示例
6.2.1 Eureka Server:springcloud-eureka
添加依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
配置 application.properties
server.port=8761spring.application.name=eureka-server#设置注册中心
eureka.instance.hostname=localhost
#告知注册中心 你不能向你自己注册
eureka.client.register-with-eureka=false
#你的主要作用是维护服务 ,不是检索服务
eureka.client.fetch-registry=false
#注册中心的地址
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka
启动类:
@SpringBootApplication
@EnableEurekaServer //启动eureka
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
6.2.2 Eureka Client:springcloud-zuul-provider
添加依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
配置 application.properties
server.port=8083
spring.application.name=06-springcloud-zuul-provider
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
启动类
@SpringBootApplication
@EnableEurekaClient
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
编写TestController
@RestController
public class TestController {@RequestMapping("/test")public String test(){return "使用了zuul网关的控制器...服务提供者test";}@RequestMapping("/test02")public String test02(){return "使用了zuul网关的控制器...服务提供者test02";}
}
6.2.3 Eureka Client:springcloud-zuul-gateway
添加依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
配置 application.properties
server.port=9000spring.application.name=06-springcloud-zuul-gatewayeureka.client.service-url.defaultZone=http://localhost:8761/eureka# 配置路由规则
zuul.routes.api-zuul.path=/api-zuul/**
zuul.routes.api-zuul.service-id=06-springcloud-zuul-provider
#或者 zuul.routes.api-zuul.serviceId
启动类
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy //激活zuul的支持
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
编写AuthFilter
@Component
public class AuthFilter extends ZuulFilter {//过滤器类型@Overridepublic String filterType() {//前置过滤器return "pre";}//执行顺序,数字越小,越优先执行@Overridepublic int filterOrder() {return 0;}// 是否启用过滤器@Overridepublic boolean shouldFilter() {return true;}//过滤器具体的操作@Overridepublic Object run() throws ZuulException {//获取请求的上下文RequestContext context = RequestContext.getCurrentContext();HttpServletRequest request = context.getRequest();String token = request.getParameter("token");if(token == null || !"123456".equals(token)){//不转发给服务器context.setSendZuulResponse(false);//权限不足context.setResponseStatusCode(401);//设置响应编码context.addZuulResponseHeader("Content-Type","text/html;charset=GB2312");//设置响应内容context.setResponseBody("非法请求!");}else {System.out.println("执行下一个过滤器");}return null;}
}
6.2.4 Eureka Client:springcloud-zuul-consumer
添加依赖
<!--豪猪依赖-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency><!--仪表盘-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency><!-- 开启健康检查-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId>
</dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
配置 application.properties
server.port=8084
spring.application.name=06-springcloud-zuul-consumer
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
启动类
@SpringBootApplication
@EnableEurekaClient
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}}
编写 RestTemplateConfig
@Configuration
public class RestTemplateConfig {/*** LoadBalanced 标记 restTemplate使用 ribbon 的 负载均衡策略访问服务的提供者* 使用了 Eureka注册中心后 restTemplate 对象上方必须添加该注解*/@Bean@LoadBalancedpublic RestTemplate restTemplate(){return new RestTemplate();}
}
编写TestController
@RestController
public class TestController {@Autowiredprivate RestTemplate restTemplate;@RequestMapping("/test")public String test(){ResponseEntity<String> result = restTemplate.getForEntity("http://06-springcloud-zuul-provider/test",String.class);return "没有经过网关的...["+result+"]";}@RequestMapping("/test02")public String test02(String token){ResponseEntity<String> result = restTemplate.getForEntity("http://06-springcloud-zuul-provider/test02?token="+token,String.class);return "经过网关的 token...["+result+"]";}
}
启动四个服务,访问http://localhost:9000/api-zuul/test,由于没有传入token:
访问http://localhost:9000/api-zuul/test02?token=123456: