P.s该博文紧接上一篇博客SpringCloud基础01
1.服务负载均衡
1.1.为什么负载均衡
为了提供并发量,有时同一个服务提供者可以部署多个(商品服务)。这个客户端在调用时要根据一定的负责均衡策略完成负载调用。
1.2.服务提供者负载均衡
此处只需要两个服务名一致,端口不一致即可
8081-application.yml:
server:
port: 8081
spring:
application:
name: PRODUCT-SERVICE #服务的名字
eureka:
client:
service-url:
#http://localhost:7081/eureka/ #单机配置
defaultZone: http://eurekaServer-7081:7081/eureka/,http://eurekaServer-7082:7082/eureka/ #集群配置
instance:
prefer-ip-address: true #当调用getHostname获取实例的hostname时,返回ip而不是host名称
ip-address: 127.0.0.1
8082-application.yml:
server:
port: 8082
spring:
application:
name: PRODUCT-SERVICE #服务的名字
eureka:
client:
service-url:
#http://localhost:7081/eureka/ #单机配置
defaultZone: http://eurekaServer-7081:7081/eureka/,http://eurekaServer-7082:7082/eureka/ #集群配置
instance:
prefer-ip-address: true #当调用getHostname获取实例的hostname时,返回ip而不是host名称
ip-address: 127.0.0.1
开启eureka服务和8081和8082服务后,便可以看到如下效果
1.3.服务消费者常见负载均衡实现技术
1.3.1.Ribbon负载均衡调用
1.3.1.1.Ribbon是什么
Ribbon是Netflix发布的云中间层服务开源项目,主要功能是提供客户端负载均衡算法。Ribbon客户端组件提供一系列完善的配置项,如,连接超时,重试等。简单的说,Ribbon是一个客户端负载均衡器,我们可以在配置文件中列出load Balancer后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器,我们也很容易使用Ribbon实现自定义的负载均衡算法。
Ribbon是一个客户端负载均衡器,它可以按照一定规则来完成一种多台服务器负载均衡调用,这些规则还支持自定义
1.3.1.2.使用方式
创建maven项目
导入pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>day72-springcloud-parent</artifactId>
<groupId>com.penny</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>order-service-ribbon-9083</artifactId>
<dependencies>
<!--公共依赖-->
<dependency>
<groupId>com.penny</groupId>
<version>1.0-SNAPSHOT</version>
<artifactId>product-interface</artifactId>
</dependency>
<!--springboot支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--eureka客户端支持 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--客户端负载均衡实现 ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
</dependencies>
</project>
创建启动类
package com.penny;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class OrderServiceRibbon9083App {
public static void main(String[] args) {
SpringApplication.run(OrderServiceRibbon9083App.class, args);
}
}
配置application.yml
server:
port: 9083
spring:
application:
name: ORDER-SERVICE-RIBBON-9083 #服务名字
eureka:
client:
service-url:
#http://localhost:7081/eureka/ #单机配置
defaultZone: http://eurekaServer-7081:7081/eureka/,http://eurekaServer-7082:7082/eureka/ #集群配置
instance:
prefer-ip-address: true #当调用getHostname获取实例的hostname时,返回ip而不是host名称
ip-address: 127.0.0.1
创建配置类
package com.penny.config;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class CfgBean {
@Bean
@LoadBalanced //开启负载均衡
public RestTemplate restTemplate(){
return new RestTemplate();
}
/*负载均衡策略:
* 1 内置 轮询(默认) 可用性过滤 权重 随机
* 2 自定义 IRule
* */
@Bean
public IRule myRule(){
return new RandomRule(); //随机策略
}
}
创建controller并测试负载均衡
package com.penny.controller;
import com.penny.domain.Product;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private RestTemplate restTemplate;
/*通过服务名完成调用*/
private final String URL_PREFIX = "http://PRODUCT-SERVICE/product/";
@GetMapping("/product/{id}")
public Product getProductById(@PathVariable("id") Long id){
//进行远程调用
String url = URL_PREFIX+id;
return restTemplate.getForObject(url, Product.class);
}
}
得到测试结果
1.3.1.3.负载均衡策略
ribbon通过服务名获取到服务列表后,要根据一定规则来选择一个服务实例来完成调用.这个规则就叫负载均衡策略.
1).IRule
通过配置不同IRule的子类,可以选择不同负载均衡策略,也就是从服务列表以特定策略选择一个服务来完成调用。当然也可以自定义。所以负载均衡策略可以分为内置和自定义。
2).内置负载均衡策略
1.3.2.Feign负载均衡
1.3.2.1.是什么
Feign是一个声明式的Web Service客户端,它的目的就是让Web Service调用更加简单。Feign提供了HTTP请求的模板,通过编写简单的接口和插入注解,就可以定义好HTTP请求的参数、格式、地址等信息。而Feign则会完全代理HTTP请求,我们只需要像调用方法一样调用它就可以完成服务请求及相关处理。Feign整合了Ribbon和Hystrix(关于Hystrix我们后面再讲),可以让我们不再需要显式地使用这两个组件。
总起来说,Feign具有如下特性:
可插拔的注解支持,包括Feign注解和JAX-RS注解;
支持可插拔的HTTP编码器和解码器;
支持Hystrix和它的Fallback;
支持Ribbon的负载均衡;
支持HTTP请求和响应的压缩。
这看起来有点像我们springmvc模式的Controller层的RequestMapping映射。这种模式是我们非常喜欢的。Feign是用@FeignClient来映射服务的。
1.3.2.2.使用方式
创建项目
导入Pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>day72-springcloud-parent</artifactId>
<groupId>com.penny</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>order-service-feign-9082</artifactId>
<dependencies>
<!--公共依赖-->
<dependency>
<groupId>com.penny</groupId>
<version>1.0-SNAPSHOT</version>
<artifactId>product-interface</artifactId>
</dependency>
<!--springboot支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--eureka客户端支持 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--feign的支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
</project>
配置application.yml
server:
port: 9082
spring:
application:
name: ORDER-SERVICE-FEIGN-9082 #服务名字
eureka:
client:
service-url:
#http://localhost:7081/eureka/ #单机配置
defaultZone: http://eurekaServer-7081:7081/eureka/,http://eurekaServer-7082:7082/eureka/ #集群配置
instance:
prefer-ip-address: true #当调用getHostname获取实例的hostname时,返回ip而不是host名称
ip-address: 127.0.0.1
创建启动类,并开启自动扫描@feignClient
package com.penny;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients //开启后会自动扫描@FeignClients注解接口
public class OrderServiceFeign9082App {
public static void main(String[] args) {
SpringApplication.run(OrderServiceFeign9082App.class, args);
}
}
创建配置类
package com.penny.config;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class CfgBean {
@Bean
@LoadBalanced //开启负载均衡
public RestTemplate restTemplate(){
return new RestTemplate();
}
/*负载均衡策略:
* 1 内置 轮询(默认) 可用性过滤 权重 随机
* 2 自定义 IRule
* */
@Bean
public IRule myRule(){
return new RandomRule(); //随机策略
}
}
创建代理类
package com.penny.clients;
import com.penny.domain.Product;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@FeignClient(value = "PRODUCT-SERVICE") //指向服务名
@RequestMapping("/product")
public interface ProductClient {
@GetMapping("{id}") //回调托底
public Product getProductById(@PathVariable("id")Long id);
}
创建测试controller
package com.penny.controller;
import com.penny.clients.ProductClient;
import com.penny.domain.Product;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private ProductClient productClient;
@GetMapping("/product/{id}")
public Product getProductById(@PathVariable("id") Long id){
//调用接口方法
return productClient.getProductById(id);
}
}
启动服务后得到测试结果如下
2.Hystrix断路器
在理想状态下,一个应用依赖的服务都是健康可用的,我们可以正常的处理所有的请求
当依赖I 阻塞时,大多数服务器的线程池就出现阻塞(BLOCK),影响整个线上服务的稳定性
同时还可能会出现服务器雪崩(雪崩现象:由于某些服务出问题,导致很多问题的现象)
2.1.解决方案
对依赖做隔离,Hystrix就是处理依赖隔离的框架,同时也是可以帮我们做依赖服务的治理和监控.。
当我们使用了Hystrix时,Hystrix将所有的外部调用都封装成一个HystrixCommand或者 HystrixObservableCommand对象,这些外部调用将会在一个独立的线程中运行。我们可以将出现 问题的服务通过熔断、降级等手段隔离开来,这样不影响整个系统的主业务
2.2.Hystrix简介
Hystrix是国外知名的视频网站Netflix所开源的非常流行的高可用架构框架。Hystrix能够完美的解决分布式系统架构中打造高可用服务面临的一系列技术难题。
Hystrix “豪猪”,具有自我保护的能力。hystrix 通过如下机制来解决雪崩效应问题。
资源隔离(限流):包括线程池隔离和信号量隔离,限制调用分布式服务的资源使用,某一个调用的服务出现问题不会影响其他服务调用。
熔断:当失败率达到阀值自动触发降级(如因网络故障/超时造成的失败率高),熔断器触发的快速失败会进行快速恢复。
降级机制:超时降级、资源不足时(线程或信号量)降级,降级后可以配合降级接口返回托底数据。
缓存:提供了请求缓存、请求合并实现。
2.2.1.服务熔断
正常情况下,断路器处于关闭状态(Closed),
如果调用持续出错或者超时,电路被打开进入熔断状态(Open),后续一段时间内的所有调用都会被拒绝(Fail Fast),
一段时间以后,保护器会尝试进入半熔断状态(Half-Open),允许少量请求进来尝试,
如果调用仍然失败,则回到熔断状态
如果调用成功,则回到电路闭合状态;
2.2.2.服务降级
有了熔断,就得有降级。所谓降级,就是当某个服务熔断之后,服务器将不再被调用,此时客户端可以自己准备一个本地的fallback回调,返回一个缺省值。
这样做,虽然服务水平下降,但好歹可用,比直接挂掉要强,当然这也要看适合的业务场景。
2.2.3.使用方式
创建项目,导入Pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>day72-springcloud-parent</artifactId>
<groupId>com.penny</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>product-service-hystrix-8083</artifactId>
<dependencies>
<!--公共依赖-->
<dependency>
<groupId>com.penny</groupId>
<version>1.0-SNAPSHOT</version>
<artifactId>product-interface</artifactId>
</dependency>
<!--springboot支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--eureka客户端支持 -->
<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>
</dependencies>
</project>
配置application.yml
server:
port: 8083
spring:
application:
name: PRODUCT-SERVICE #服务的名字
eureka:
client:
service-url:
#http://localhost:7081/eureka/ #单机配置
defaultZone: http://eurekaServer-7081:7081/eureka/,http://eurekaServer-7082:7082/eureka/ #集群配置
instance:
prefer-ip-address: true #当调用getHostname获取实例的hostname时,返回ip而不是host名称
ip-address: 127.0.0.1
创建启动类并开启@EnableHystrix
package com.penny;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
@SpringBootApplication
@EnableEurekaClient
@EnableHystrix //开启Hystrix,熔断和降级才会生效
public class ProductServiceHystrix8083App {
public static void main(String[] args) {
SpringApplication.run(ProductServiceHystrix8083App.class, args);
}
}
创建测试controller
package com.penny.controller;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.penny.domain.Product;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/product")
public class ProductController {
//restfull风格
@GetMapping("{id}")
@HystrixCommand(fallbackMethod = "getProductByIdFallback")
public Product getProductById(@PathVariable(name = "id")Long id){
//提供一个Bug,测试一个熔断,其余正常访问
if(id.intValue()==2){
throw new RuntimeException("错了错了!!");
}
return new Product(id,"阿莫西林-8082");
}
//提供一个降级处理方法
private Product getProductByIdFallback(Long id){
return new Product(id,"系统已经报错了");
}
}
服务启动后,正常情况下得到如下结果
试错后,得到如下结果
2.2.4.Feign实现Hystrix
创建项目导入pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>day72-springcloud-parent</artifactId>
<groupId>com.penny</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>order-service-feign-hystrix-9084</artifactId>
<dependencies>
<!--公共依赖-->
<dependency>
<groupId>com.penny</groupId>
<version>1.0-SNAPSHOT</version>
<artifactId>product-interface</artifactId>
</dependency>
<!--springboot支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--eureka客户端支持 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--feign的支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
</project>
配置application.yml
server:
port: 9084
spring:
application:
name: ORDER-SERVICE-FEIGN-9084 #服务名字
eureka:
client:
service-url:
#http://localhost:7081/eureka/ #单机配置
defaultZone: http://eurekaServer-7081:7081/eureka/,http://eurekaServer-7082:7082/eureka/ #集群配置
instance:
prefer-ip-address: true #当调用getHostname获取实例的hostname时,返回ip而不是host名称
ip-address: 127.0.0.1
feign:
hystrix:
enabled: true #开启熔断支持
client:
config:
remote-service: #服务名,填写default为所有服务
connectTimeout: 3000
readTimeout: 3000
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000
创建配置类.
package com.penny.config;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class CfgBean {
@Bean
@LoadBalanced //开启负载均衡
public RestTemplate restTemplate(){
return new RestTemplate();
}
/*负载均衡策略:
* 1 内置 轮询(默认) 可用性过滤 权重 随机
* 2 自定义 IRule
* */
@Bean
public IRule myRule(){
return new RandomRule(); //随机策略
}
}
创建代理接口
package com.penny.clients;
import com.penny.domain.Product;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@FeignClient(value = "PRODUCT-SERVCIE",fallbackFactory =
ProductClientFallbackFactory.class)
@RequestMapping("/product")
public interface ProductClient {
@GetMapping("/{id}") //回调托底
public Product getProductById(@PathVariable("id")Long id);
}
创建托底类
package com.penny.clients;
import com.penny.domain.Product;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
//托底类
@Component
public class ProductClientFallbackFactory implements FallbackFactory<ProductClient> {
//返回托底类,里面每个方法都有一个托底方法
public ProductClient create(Throwable throwable) {
return new ProductClient() {
public Product getProductById(Long id) {
return new Product(id,"系统报错了!!!");
}
};
}
}
创建启动类并开启@EnableFeignClients
package com.penny;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients //开启后会自动扫描@FeignClients注解接口
public class OrderServiceFeign9084App {
public static void main(String[] args) {
SpringApplication.run(OrderServiceFeign9084App.class, args);
}
}
创建测试controller
package com.penny.controller;
import com.penny.clients.ProductClient;
import com.penny.domain.Product;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private ProductClient productClient;
@GetMapping("/product/{id}")
public Product getProductById(@PathVariable("id") Long id){
//调用接口方法
return productClient.getProductById(id);
}
}
服务启动后,由于在配置application.yml时做了超时处理,所以便会得到如下结果
3.Zuul路由网关
3.1.是什么.
Zuul 是netflix开源的一个API Gateway 服务器, 本质上是一个web servlet应用。
Zuul 在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架。Zuul 相当于是设备和 Netflix 流应用的 Web 网站后端所有请求的前门,也要注册入Eureka.
3.2.为什么需要
微服务架构体系中,通常一个业务系统会有很多的微服务,比如:OrderService、ProductService、UserService…,为了让调用更简单,一般会在这些服务前端再封装一层,类似下面这样:
前面这一层俗称为“网关层”,其存在意义在于,将"1对N"问题 转换成了"1对1”问题(路由),同时在请求到达真正的微服务之前,可以做一些预处理(过滤),比如:来源合法性检测,权限校验,反爬虫之类…
3.3使用方式
创建项目,导入pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>day72-springcloud-parent</artifactId>
<groupId>com.penny</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>zuul-gateway-6081</artifactId>
<dependencies>
<!--springboot支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<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>
</dependencies>
</project>
配置application.yml
server:
port: 6081
spring:
application:
name: ZUUL-GATEWAY-6081 #服务的名字
eureka:
client:
service-url:
#http://localhost:7081/eureka/ #单机配置
defaultZone: http://eurekaServer-7081:7081/eureka/,http://eurekaServer-7082:7082/eureka/ #集群配置
instance:
prefer-ip-address: false #当调用getHostname获取实例的hostname时,返回ip而不是host名称
instance-id: gateway-6081
zuul:
routes: #路由们 什么地址转发给那个服务
product.serviceId: product-service #服务名的小写
product.path: /product/** #以/product开头的地址统统转发给 product-servcie服务处理
ignored-services: "*" #所有服务都不允许以服务名来访问
prefix: "/services/" #为所有服务的访问都加上统一的前缀
retryable: true
ribbon:
ConnectTimeout: 250 # 连接超时时间(ms)
ReadTimeout: 2000 # 通信超时时间(ms)
OkToRetryOnAllOperations: true # 是否对所有操作重试
MaxAutoRetriesNextServer: 2 # 同一服务不同实例的重试次数
MaxAutoRetries: 1 # 同一实例的重试次数
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMillisecond: 3000 # 熔断超时时长:3000ms
创建启动类并开启@EnableZullProxy网关
package com.penny;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableZuulProxy //启动zuul
public class ZuulGateway6081App {
public static void main(String[] args) {
SpringApplication.run(ZuulGateway6081App.class, args);
}
}
创建拦截器
package com.penny.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
public class LoginFilter extends ZuulFilter {
//过滤器类型
public String filterType() {
return "pre";
}
//过滤器顺序
public int filterOrder() {
return 1;
}
//是否让改过滤器生效
public boolean shouldFilter() {
return true;
}
//实现登录判断的逻辑
public Object run() throws ZuulException {
//获取请求上下文
RequestContext currentContext = RequestContext.getCurrentContext();
//获取请求
HttpServletRequest request = currentContext.getRequest();
//从请求头中获取token
String token = request.getHeader("token");
//判断,成功登陆,失败报错
if(null == token || "".equals(token)){
//校验失败,报错
currentContext.setSendZuulResponse(false);
//返回错误码
currentContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
}
//正常则登陆
return null;
}
}
服务启动后发现,如果没有传入token,访问会被拒绝
传入token则可以正常访问
4.SpringCloud分布式配置中心
4.1.是什么
在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。在Spring Cloud中,有分布式配置中心组件spring cloud config ,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中。在spring cloud config 组件中,分两个角色,一是config server,二是config client。
4.2使用方式
4.2.1.服务端配置
github创建配置文件
创建项目并导入pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>day72-springcloud-parent</artifactId>
<groupId>com.penny</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>config-server-5081</artifactId>
<dependencies>
<!--springboot支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--eureka客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--配置中心支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
</dependencies>
</project>
创建application.yml
server:
port: 5081
eureka:
client:
service-url:
#http://localhost:7081/eureka/ #单机配置
defaultZone: http://eurekaServer-7081:7081/eureka/,http://eurekaServer-7082:7082/eureka/ #集群配置
instance:
prefer-ip-address: false #当调用getHostname获取实例的hostname时,返回ip而不是host名称
spring:
application:
name: config-server-5081
cloud:
config:
server:
git:
uri: #此处填你的创建的githun配置地址路径
username: #此处填你的github账号
password: #此处填你的github密码
创建启动类并开启@EnableConfigServer服务端配置
package com.penny;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication
//开启配置中心
@EnableConfigServer
public class ConfigServer5081App {
public static void main(String[] args) {
SpringApplication.run(ConfigServer5081App.class, args);
}
}
服务启动后正常访问结果如下