第一章-项目准备
准备环境
1.JDK 1.8+
2.idea 或eclipse编码工具
所需知识
1.有一定的java代码阅读能力
2.学习过SpringBoot
maven创建父项目
创建项目名为:SpringCloud-demo
创建父项目的好处:以后好更新版本
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>SpringCloud-demo</groupId>
<artifactId>SpringCloud-demo</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<!--模块名-->
<modules>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR2</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
第二章-注册中心-springcloud-server
创建-springcloud-Eureka-项目
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-server</artifactId>
<groupId>SpringCloud-demo</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>springcloud-server</groupId>
<artifactId>springcloud-Eureka</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
</project>
开启一个服务注册中心
启动一个服务注册中心
启动一个服务注册中心的方式很简单,就是在Spring Boot的入口类上
添加一个@EnableEurekaServer注解,如下:
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerRunApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerRunApplication.class, args);
}
}
配置application.yml
server:
#端口
port: 9000
eureka:
instance:
#服务注册中心实例的主机名
hostname: localhost
#ip-address: 固定ip地址
instance-id: ${spring.cloud.client.ip-address}:${server.port}
preferIpAddress: true
server:
#关闭自我保护机制,防止失效的服务也被一直访问 (开发环境)
enable-self-preservation: false
#该配置可以修改检查失效服务的时间,每隔5s检查失效服务,默认该配置是 60s (开发环境)
eviction-interval-timer-in-ms: 5000
client:
#是否向服务注册中心注册自己
registerWithEureka: false
#是否检索服务
fetchRegistry: false
#服务注册中心的配置内容,指定服务注册中心的位置
serviceUrl:
defaultZone: http://localhost:9100/eureka/
测试
在浏览器中输入:http://localhost:9000/就能够看到如下页面:
第三章-提供者-springcloud-provider
创建 springcloud-provider-1-项目
<?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-demo</artifactId>
<groupId>SpringCloud-demo</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>springcloud-provider</groupId>
<artifactId>springcloud-provider</artifactId>
<dependencies>
<!-- 服务发现客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- spring-boot-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
</project>
配置application.yml
#将服务注册到注册中心
eureka:
client:
serviceUrl:
defaultZone: http://localhost:9000/eureka/
#healthcheck:
#enabled: true #开启自定义健康检查
instance:
#eureka服务器在接收到最后一个心跳之后等待的时间,然后才能从列表中删除此实例 默认90s(开发环境)
lease-expiration-duration-in-seconds: 10
#eureka客户端需要向eureka服务器发送心跳的频率 默认30s (开发环境)
lease-renewal-interval-in-seconds: 1
# ip地址
#ip-address: 固定ip地址
#instance-id: ${spring.cloud.client.ip-address}:${server.port}
#preferIpAddress: true
#配置服务名称及端口
server:
port: 9001
spring:
application:
name: springcloud-provider
自定义属性 app name
kd:
app:
name: 提供者-1
创建controller提供服务
@RestController
public class TestController {
@Value("${server.port}")
String port;
@Value("${spring.application.name}")
String name;
@Value("${kd.app.name}")
String appName;
@RequestMapping("/test")
public String test() {
return appName+"上线测试:"+name+":"+port;
}
}
启动提供者
@SpringBootApplication
@EnableDiscoveryClient //注册服务到注册中心去
public class ProviderRun_1 {
public static void main(String[] args) {
SpringApplication.run(ProviderRun_1.class, args);
}
}
浏览器查看
再查看注册中心地址 http://localhost:9000/
发现服务列表有 springcloud-provider
显示ip而不是主机的方法
找到 application.yml 以下属性把#去掉就行了
#instance-id: ${spring.cloud.client.ip-address}:${server.port}
#preferIpAddress: true
注意显示IP和主机的区别?
1.显示主机方式:好处是提供服务用主机名比较直观,但是要添加到hosts里去,
不然不同机器是识别不了服务的。
2.显示ip的方式:以IP地址显示,局域网内访问很方便。
3.推荐方式:组合用,开启preferIpAddress: true 即可
第四章-服务消费者(ribbon方式)
maven创建 spirngcloud-ribbon-client
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-demo</artifactId>
<groupId>SpringCloud-demo</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spirngcloud-ribbon-client</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--添加Hystrix依赖 断路器容错保护-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--监控中心-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
</project>
创建Ribbon启动类
@SpringBootApplication
@EnableDiscoveryClient
@RestController
public class RibbonRun {
public static void main(String[] args) {
SpringApplication.run(RibbonRun.class, args);
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
@Autowired
RestTemplate restTemplate;
@RequestMapping(value = "/test")
public String test(){
return restTemplate.getForObject("http://springcloud-provider/test",String.class);
}
}
配置application.yml
#将服务注册到注册中心
eureka:
client:
serviceUrl:
defaultZone: http://localhost:9000/eureka/
#healthcheck:
#enabled: true #开启自定义健康检查
instance:
#eureka服务器在接收到最后一个心跳之后等待的时间,然后才能从列表中删除此实例 默认90s(开发环境)
lease-expiration-duration-in-seconds: 10
#eureka客户端需要向eureka服务器发送心跳的频率 默认30s (开发环境)
lease-renewal-interval-in-seconds: 1
server:
port: 9004
#配置服务名称及端口
spring:
application:
name: spirngcloud-ribbon-client
浏览器查看结果
http://localhost:9004/test
第五章-客户端负载均衡
什么是负载均衡?
负载均衡是我们处理高并发、缓解网络压力和进行服务端扩容的解决方案
负载均衡分为两种
1.服务端负载均衡
Nginx就是服务端负载均衡的例子
由Nginx 分发器统一反向代理请求地址
2.客户端负载均衡
不是统一分发,而是由客户端自己选择,如果你学过dubbo,它就是客户端负载均衡
Ribbo消费者是否支持负载均衡?
可以的,Ribbo的实现本身就是客户端负载均衡,
通过RestTemplate来访问接口服务的,
只要加@LoadBalanced注解来达到负载均衡是不是很简单
Ribbo负载均衡运行机制是什么?
Ribbo是一个基于HTTP和TCP的客户端负载均衡器,
当我们将Ribbon和Eureka一起使用时,Ribbon会从Eureka注册中心去获取服务端列表,
然后进行轮询访问以到达负载均衡的作用,客户端负载均衡中也需要心跳机制去维护服务端清单的有效性,
当然这个过程需要配合服务注册中心一起完成
常用的负载均衡策略
- RandomRule(随机策略)
- RoundRobinRule(轮询策略-默认策略)
- RetryRule(重试策略)
- WeightedResponseTimeRule(权重策略)
测试负载均衡
1.需要两个提供者项目
springcloud-provider-1(已有,项目端口9001)
springcloud-provider-2-项目端口是9003
和springcloud-provider-1项目一样但是就端口不一样,和自定义属性值不一样
相当于有springcloud-provide提供者两个实例,供消费者消费
2.启动两个提供者项目,查看注册中心
发现springcloud-provider服务up数量是2
3.启动Ribbo消费者来消费服务
不断刷新浏览器访问 http://localhost:9004/test
你会发现:
发现:
Ribbo 消费者会轮询消费注册列表的两个提供者服务
第六章-服务消费者(feign方式)
什么是 Feign ?
Feign是一套基于Netflix Feign实现的声明式服务调用客户端。
它使得编写Web服务客户端变得更加简单。通过创建接口并用注解来配置
它既可完成对Web服务接口的绑定。它具备可插拔的注解支持,
包括Feign注解、JAX-RS注解。它也支持可插拔的编码器和解码器。
也同时整合了Ribbon和Eureka来提供均衡负载的HTTP客户端实现。
总之,Feign是基于Ribbon实现,使得接口更加规范化,更有阅读性并且更加简单化,
也具有负载均衡的能力
创建 springcloud-feign 项目
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-demo</artifactId>
<groupId>SpringCloud-demo</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-feign</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
</project>
配置application.yml
#配置服务名称及端口
spring:
application:
name: springcloud-feign
server:
port: 9005
#将服务注册到注册中心
eureka:
client:
serviceUrl:
defaultZone: http://localhost:9000/eureka/
#healthcheck:
#enabled: true #开启自定义健康检查
instance:
#eureka服务器在接收到最后一个心跳之后等待的时间,然后才能从列表中删除此实例 默认90s(开发环境)
lease-expiration-duration-in-seconds: 10
#eureka客户端需要向eureka服务器发送心跳的频率 默认30s (开发环境)
lease-renewal-interval-in-seconds: 1
Feign启动类
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class FeignApplication {
public static void main(String[] args) {
SpringApplication.run(FeignApplication.class, args);
}
}
Feign消费服务接口
定义一个feign接口,通过@ FeignClient(“服务名”),
来指定调用哪个服务。比如在代码中调用了springcloud-provider服务的“/test”接口,代码如下:
@FeignClient(value = "springcloud-provider")
public interface TestFeign {
@RequestMapping(value = "/test")
String testByFeign();
}
注意:服务名大小写无所谓,@FeignClient 会把接口类交给spring所管理
也就是说是可以@Autowired注入的
编写controller类调用服务
@RestController
public class TestController {
@Autowired
TestFeign testFeign;// 注入 Feign接口
@RequestMapping(value = "/test")
public String test(){
return testFeign.testByFeign();
}
}
FeignApplication类启动测试
不断刷新浏览器地址 http://localhost:9005/test
从上面也能看的出来,Feign也是能消费服务,并且也有负载均衡
从而也证明了Feign是基于Ribbon实现
并使用注解接口使其更简单(@ FeignClient(“服务名”))
参数传递
上面是一个简单的调用案例,这个例子中没有涉及到参数的传递,那接下来看看参数的例子
再增加提供者三种情况的参数的服务接口,分别如下:
// 测试带普通参数
@RequestMapping("/testByParam")
public String testByParam(String from) {
return appName+"上线测试:"+name+":"+port+"来自:"+from;
}
// 测试带多个普通参数Map
@RequestMapping("/testByMap")
public String testByParam(@RequestParam Map<String,Object> map) {
return appName+"上线测试:"+name+":"+port+"用户:"+map.get("name");
}
// 测试参数是对象的情况
@RequestMapping("/testByRequestBody")
public String testByRequestBody(@RequestBody User user) {
return appName+"上线测试:"+name+":"+port+"用户:"+user.getName();
}
FeignClient 这边也增加对应的消费接口的方法
// 测试带普通参数
@RequestMapping(value = "/testByParam")
String testByParam(@RequestParam("from") String from);
// 测试带多个普通参数Map
@RequestMapping(value = "/testByMap")
String testByMap(Map<String,Object> map);
// 测试参数是对象的情况 @RequestBody User user
@RequestMapping(value = "/testByRequestBody",method = RequestMethod.POST)
String testByRequestBody(@RequestBody User user);
注意,在SpringMVC中,@RequestParam,如果不指定value,则默认采用参数的名字作为其value,如上面的例子
但是在Feign中,这个value必须明确指定,否则会报错。
如果是pojo 实体类对象,服务提供者这方必须加上 @RequestBody注解
测试
Feign拦截器
可以再请求调用服务拦截做一些事情,比如日志记录、权限的判断
创建一个配置类,spirng会自动扫描的
@Configuration
public class FeignConfig {
@Bean
public RequestInterceptor getRequestInterceptor(){
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate requestTemplate) {
/** 设置请求头信息 **/
// requestTemplate.header("Content-Type", "application/json");
// 可以做日志记录
System.out.println("自定义拦截器");
}
};
}
}
当然也能有多个拦截器,多加一个拦截器@bean就行了
@Configuration
public class FeignConfig {
@Bean
public RequestInterceptor getRequestInterceptor(){
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate requestTemplate) {
/** 设置请求头信息 **/
// requestTemplate.header("Content-Type", "application/json");
// 可以做日志记录
System.out.println("自定义拦截器-日志记录");
}
};
}
@Bean
public RequestInterceptor getRequestInterceptor(){
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate requestTemplate) {
/** 设置请求头信息 **/
// requestTemplate.header("Content-Type", "application/json");
// 可以做权限判断
System.out.println("自定义拦截器2-权限判断");
}
};
}
}
第七章-断路器(Hystrix)
Hystrix断路器的作用
服务断路容错:微服务往往服务众多,各服务之间相互调用,若消费者在调用提供者时出现由网络,
提供者服务自身问题等导致接口出现故障或延迟;此时消费者的请求不断增加,
务必会出现因等待响应而造成任务积压,线程无法释放,进一步导致服务的瘫痪。
出现雪崩效应
既然微服务架构存在这样的隐患,那么针对服务的容错性必然会进行服务降级,
依赖隔离,断路器等一线列的服务保护机制。
其实有点类似家用的保险丝作用
Feign没使用Hystrix断路器的情况
可以向提供者服务接口加上一段错误代码
@RequestMapping("/test")
public String test() {
int a=1/0;// 除数不能为0
return appName+"上线测试:"+name+":"+port;
}
重新启动提供者,浏览器测试结果
调用了错误的接口,出现500错误的界面提示,这是我不希望看见的
希望看见调用错误,界面友好提示而不是报500错误界面
Feign使用Hystrix断路器的情况、
需要向springcloud-feign项目添加依赖
<!--添加Hystrix依赖 断路器容错保护 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
修改springcloud-feign项目启动类
添加 @EnableHystrix 注解
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableHystrix//开启断路器功能
public class FeignApplication {
public static void main(String[] args) {
SpringApplication.run(FeignApplication.class, args);
}
}
修改 application.yml 添加属性
#开启hystrix 指标
feign:
hystrix:
enabled: true
增加一个fallback错误回调类就行了
@Component
public class TestFeignFallback implements TestFeign {
@Override
public String testByFeign() {
return "error";
}
@Override
public String testByParam(String from) {
return "error";
}
@Override
public String testByMap(Map<String, Object> map) {
return "error";
}
@Override
public String testByRequestBody(User user) {
return "error";
}
}
关联fallback = TestFeignFallback.class 一旦错误就回调同名称的方法
@FeignClient(value = "springcloud-provider",fallback = TestFeignFallback.class)
public interface TestFeign {
@RequestMapping(value = "/test")
String testByFeign();
// 测试带普通参数
@RequestMapping(value = "/testByParam")
String testByParam(@RequestParam("from") String from);
// 测试带多个普通参数Map
@RequestMapping(value = "/testByMap")
String testByMap(Map<String,Object> map);
// 测试参数是对象的情况 @RequestBody User user
@RequestMapping(value = "/testByRequestBody",method = RequestMethod.POST)
String testByRequestBody(@RequestBody User user);
}
重启springcloud-feign项目,浏览器测试 http://localhost:9005/test
在ribbon使用断路器
需要向spirngcloud-ribbon-client项目添加依赖
<!--添加Hystrix依赖 断路器容错保护-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
修改spirngcloud-ribbon-client项目启动类
添加 @EnableHystrix 注解
@HystrixCommand(fallbackMethod = "error")和error方法
@SpringBootApplication
@EnableDiscoveryClient
@RestController
@EnableHystrix
public class RibbonRun {
public static void main(String[] args) {
SpringApplication.run(RibbonRun.class, args);
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
@Autowired
RestTemplate restTemplate;
@RequestMapping(value = "/test")
@HystrixCommand(fallbackMethod = "error")
public String test(){
return restTemplate.getForObject("http://springcloud-provider/test",String.class);
}
public String error() {
return "error";
}
一旦test接口报错就会降级调用error方法
第八章-Hystrix Dashboard监控面板
创建hystrixDashboard项目
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>SpringCloud-demo</artifactId>
<groupId>SpringCloud-demo</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-hystrixDashboard</artifactId>
<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-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
</dependencies>
</project>
配置 application.yml
#将服务注册到注册中心
eureka:
client:
serviceUrl:
defaultZone: http://localhost:9000/eureka/
#healthcheck:
#enabled: true #开启自定义健康检查
instance:
#eureka服务器在接收到最后一个心跳之后等待的时间,然后才能从列表中删除此实例 默认90s(开发环境)
lease-expiration-duration-in-seconds: 10
#eureka客户端需要向eureka服务器发送心跳的频率 默认30s (开发环境)
lease-renewal-interval-in-seconds: 1
server:
port: 9006
spring:
application:
name: springcloud-hystrixDashboard
创建 HystrixDashboardApplicat启动类
@SpringBootApplication
@EnableHystrixDashboard
@EnableDiscoveryClient
public class HystrixDashboardApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixDashboardApplication.class, args);
}
}
修改springcloud-feign项目
pom.xml
<!--监控中心-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
增加 application.yml 属性(必须要加)
端点管理
management:
endpoints:
web:
exposure:
include: "*"
启动项目测试
启动 springcloud-feign、hystrixDashboard、springcloud-provider-1 项目
1.浏览器测试 http://localhost:9006/hystrix
2.访问几次消费接口地址 http://localhost:9005/test
3.如图所示输入监控地址:http://localhost:9005/actuator/hystrix.stream
4.点击Monitor Stream按钮
注意:要消费几次服务接口,要不然没有监控数据
监控数据展示
第九章-turbine(Hystrix监控数据集群)
当Hystrix消费者多个时需要把每一个消费监控信息整合在一个turbine集群面板上
创建 springcloud-turbine项目
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>SpringCloud-demo</artifactId>
<groupId>SpringCloud-demo</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-turbine</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
</project>
配置 application.yml
注意 指定了需要收集监控信息的服务名,多个以“,”进行区分
#将服务注册到注册中心
eureka:
client:
serviceUrl:
defaultZone: http://localhost:9000/eureka/
#healthcheck:
#enabled: true #开启自定义健康检查
instance:
#eureka服务器在接收到最后一个心跳之后等待的时间,然后才能从列表中删除此实例 默认90s(开发环境)
lease-expiration-duration-in-seconds: 10
#eureka客户端需要向eureka服务器发送心跳的频率 默认30s (开发环境)
lease-renewal-interval-in-seconds: 1
server:
port: 9007
spring:
application:
name: springcloud-turbine
turbine:
#指定了需要收集监控信息的服务名,多个以“,”进行区分
appConfig: springcloud-feign
clusterNameExpression: new String("default")
combineHostPort: true
创建启动类
@SpringBootApplication
@EnableDiscoveryClient
@EnableAutoConfiguration
@EnableTurbine
public class TurbineApplication {
public static void main(String[] args) {
SpringApplication.run(TurbineApplication.class, args);
}
}
启动项目测试
0.启动注册中心
1.启动springcloud-feign
2.启动springcloud-provider-1
3.启动springcloud-hystrixDashboard
4.启动springcloud-turbine
1.浏览器测试 http://localhost:9006/hystrix
2.访问几次消费接口地址 http://localhost:9005/test
3.如图所示输入监控地址:http://localhost:9007/turbine.stream
4.点击Monitor Stream按钮
注意:要消费几次服务接口,要不然没有监控数据
第十章-zuul-路由网关
zuul 介绍
我们知道微服务就是把一个大的项目拆分成很多小的独立服务项目,服务项目之间相互调用构建系统生态体系,那在这之间就有问题, 如何控制权限?如何分发路由?如何统一记录访问日志?为了解决这个问题就有了zuul网关,其实它可以理解成过滤器
为微服务架构提供了前门保护的作用,同时将权限控制这些较重的非业务逻辑内容迁移到服务路由层面,使得服务集群主体能够具备更高的可复用性和可测试性。
创建springcloud-zuul项目
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>SpringCloud-demo</artifactId>
<groupId>SpringCloud-demo</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-zuul</artifactId>
<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>
</project>
配置信息application.yml
#配置服务名称及端口
spring:
application:
name: springcloud-zuul
server:
port: 9008
#将服务注册到注册中心
eureka:
client:
serviceUrl:
defaultZone: http://localhost:9000/eureka/
#healthcheck:
#enabled: true #开启自定义健康检查
instance:
#eureka服务器在接收到最后一个心跳之后等待的时间,然后才能从列表中删除此实例 默认90s(开发环境)
lease-expiration-duration-in-seconds: 10
#eureka客户端需要向eureka服务器发送心跳的频率 默认30s (开发环境)
lease-renewal-interval-in-seconds: 1
默认zuul-路由
zuul 路由,默认情况下,Eureka上所有注册的服务都会被Zuul创建映射关系来进行路由 如果映射规则我们什么都不写,系统也给我们提供了一套默认的配置规则,默认的配置 zuul.routes.应用服务名=/应用服务名/**
自定义路由
举例说明
zuul.routes.api-a.path=/api-a/**
zuul.routes.api-a.serviceId=springcloud-feign
我们说当我的访问地址符合/api-a/**规则的时候,会被自动定位到springcloud-feign服务上去,可以用下面一行代码来代替,如下:
zuul.routes.springcloud-feign=/api-a/**
也可以忽视不创建路由规则
zuul.ignored-services=springcloud-provider
定义过滤器
来个简单权限业务,如果有accessToken就放行,没有就提示无访问权限
package org.kd.filter;
import javax.servlet.http.HttpServletRequest;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
public class AccessTokenFilter extends ZuulFilter {
// run:过滤器的具体逻辑。默认是放行的
// 通过ctx.setSendZuulResponse(false)令zuul过滤该请求,不对其进行路由,
// 然后通过ctx.setResponseStatusCode(401)设置了其返回的错误码,
// 也可以进一步优化比如,通过ctx.setResponseBody(body)对返回body内容进行编辑等。
@Override
public Object run() throws ZuulException {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
Object accessToken = request.getParameter("accessToken");
System.out.println("accessToken:" + accessToken);
if (accessToken == null) {
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
ctx.addZuulResponseHeader("content-type","text/html;charset=utf-8");
ctx.setResponseBody("无权访问-没有accessToken");
return null;
}
return null;
}
// shouldFilter:判断该过滤器是否需要被执行。
// true表示该过滤器对所有请求都会生效。
// 实际运用中我们可以利用该函数来指定过滤器的有效范围。
@Override
public boolean shouldFilter() {
return true;
}
// 过滤器的执行顺序。值越小越先执行
@Override
public int filterOrder() {
return 0;
}
// filterType:过滤器的类型,它决定过滤器在请求的哪个生命周期中执行。
// pre:可以在请求被路由之前调用
// route:在路由请求时候被调用
// post:在route和error过滤器之后被调用
// error:处理请求时发生错误时被调用
@Override
public String filterType() {
return "pre";
}
}
创建启动类
@SpringBootApplication
@EnableZuulProxy// @EnableZuulProxy 自动加载过滤器bean
@EnableDiscoveryClient
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
// AccessToken访问权限拦截
@Bean
public AccessTokenFilter accessTokenFilter() {
return new AccessTokenFilter();
}
}
设置过滤器
修改启动类,添加过滤器
@SpringBootApplication
@EnableZuulProxy// @EnableZuulProxy 自动加载过滤器bean
@EnableDiscoveryClient
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
// AccessToken访问权限拦截
@Bean
public AccessTokenFilter accessTokenFilter() {
return new AccessTokenFilter();
}
}
浏览器启动测试
0.启动注册中心
1.启动springcloud-zuul项目
2.启动springcloud-provider-1项目
3.启动springcloud-feign项目
注意:需要zuul路由转发的
http://localhost:9008/springcloud-feign/test
http://localhost:9008/springcloud-feign/test?accessToken=100