SpringCloud入门

it2025-02-01  14

Spring Boot和Spring Cloud

SpringCloud Spring Cloud是-个分布式的整体解决方案。Spring Cloud为开发者提供了在分布式系统(配 置管理,服务发现,熔断,路由,微代理,控制总线,- -次性token,全局琐,leader选举, 分 布式session,集群状态)中快速构建的工具,使用Spring Cloud的开发者可以快速的启动服务 或构建应用、同时能够快速和云平台资源进行对接。 ●SpringCloud分布式开发五大常用组件 ●服务发现一 Netflix Eureka ●客服端负载均衡一Netflix Ribbon ●断路器一 Netflix Hystrix ●服务网关一-Netlix Zuul ●分布式配置一 -Spring Cloud Config

快速开始Cloud

注册中心

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RGNq6ueY-1603278766654)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\1584929037174.png)]

配置文件

server: port: 8761 eureka: instance: hostname: eureka-server #eureka实例的主机名字 client: register-with-eureka: false #不把自己注册到 eureka fetch-registry: false #不从eureka上获取服务的注册信息 service-url: defaultZone: http://localhost:8761/eureka/

在启动类上添加注解

@EnableEurekaServer //启动注册中心

服务提供者

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qilRvHXc-1603278766658)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\1584929138810.png)]

配置文件

server: port: 8002 spring: application: name: provider-ticket eureka: instance: prefer-ip-address: true #注册服务时使用ip地址 client: service-url: defaultZone: http://localhost:8761/eureka/

服务消费者

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HhK6zVEo-1603278766661)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\1584929282691.png)]

配置文件

spring: application: name: consumer-user server: port: 8200 eureka: instance: prefer-ip-address: true #注册服务时使用ip地址 client: service-url: defaultZone: http://localhost:8761/eureka/

启动类添加 获取服务注解 开启负载均衡

@EnableDiscoveryClient //开启获取服务 @SpringBootApplication public class ConsumerUserApplication { public static void main(String[] args) { SpringApplication.run(ConsumerUserApplication.class, args); } @LoadBalanced //使用负载均衡 @Bean public RestTemplate restTemplate(){ return new RestTemplate(); } }

开始获取服务

@RestController public class UserController { @Autowired RestTemplate template; @GetMapping("/buy") public String buyTicket(String name){ //第一个参数为注册中心的服务名 , 第二个参数返回值类型; String s = template.getForObject("http://PROVIDER-TICKET/ticket",String.class); return name+"购买了"+s; } }

SpringBoot

Spring --> SpringMvc --> Tomcat 简化配置值

舍弃笨重的xml 改用 yml 或properties

产品独立运行

产品可独立运行,打成jar包,内置了tomcat 或其他servlet容器,契合微服务的理念;

强大的场景启动器

每一个特定场景需求都封装成了有个starter,只需要导入这个启动器就有了这个场景所需的一切,其中包括针对这个场景的自动化配置,依赖信息;

重要的组成部分

starter 启动器 @Enablexxx 注解 功能启用 yml 或 propertires 配置文件 主启动类

相关注解

@Configuration 注解标记一个类后,该类成为配置类,加载这个类中的配置可以取代以前的xml 配置文件 @Bean 注解把一个类的对象加入IOC容器 @Import 相对于@Bean,能更便捷的将已给类jiaruIOC容器 @Conditional注解 一个类满足特定条件时才加如IOC容器 @ComponentScan 指定IOC容器扫描的包,自动扫描指定的包下的注解 等同于 xml context:component-scan; @ComponentScan({"全限定包名1","全限定包名2"}) 可以扫描多个包 @SpringBootConfiguration @Configuration注解的 SpringBoot版 @Targer(ElementType.Type) @Retention(RetentionPolicy.RUNTIME) @Documented @COnfiguration public @interface SpringBootConfiguration{ } @EnableAutoConfigurtion 启动自动化配置 @AutoConfigurationPackage 指定自动配置的包 @SpringBootAppliction 注解相当于 ssm中的总配置文件,包含了 @SpringBootConfiguration @ComponentScan @EnableAutoConfigurtion ...

SpringBoot 工作原理

读取spring.factories文件

SpringBoot启动时会读取spring-boot-autoconfigure-2.2.5.RELEASE.jar包下的ME TA-INF/spring.factories文件。读取 org.springframework.boot.autoconfigure.EnableAutoConfiguration属性的值加载自动配置类。

加载XxxProperties类

根据自动配置类中指定的XxxPropertes类设置自动配置的属性值,开发者也可以根据XxxProperties类中指定的属性在yml 配置文件中修改自动配置。.

根据@ConditionalXxx注解决定加载哪些组件

SpringBoot通过@ConditionalXxx注解指定特定组件加入IOC容器时所需要具备的特定条件。这个组件会在满足条件时加入 I0C容器。

整合bootRedis

导入依赖

<!-- redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>

boot 无法连接redis

解决办法: 查看有没有启动Redis服务器。 redis的配置application.yml(或application.properties)中 spring.redis.timeout连接超时时间(毫秒)中设置不能为0, 一般修改如下:spring.redis.timeout=5000。 找到redis的配置文件 redis.conf : 执行 vim redis.conf 3.1 protected-mode yes 改为 protected-mode no (即该配置项表示是否开启保护模式,默认是开启,开启后Redis只会本地进行访问,拒绝外部访问)。 3.2 注释掉 bin127.0.0.1 即 #bin 127.0.0.1 (ps: 不注释掉,表示指定 redis 只接收来自于该 IP 地址的请求,注释掉后,则表示将处理所有请求)。 如果在Redis中没有配置requirepass ,那么在application.properties(或application.yaml)中就不要写spring.redis.password。

Redis (error) NOAUTH Authentication required.解决方法

出现认证问题,应该是设置了认证密码,输入密码既可以啦

注意密码是字符串形式!

cdm 命令

//密码 auth "yourpassword" //查询所有的 keys keys * //查询指定 key的值 get key

SpringCloud 的组件

注册中心:Eureka 客户端负载均衡:Ribbon 声明式远程方法调用:Feign 服务降级 熔断 :Hystrix; 网关:Zuul

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ka3ibEb2-1603278766665)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\1585097293833.png)]

创建 Cloud项目

1.创建注册中心

创建boot 项目

导入依赖

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> <version>2.2.2.RELEASE</version> </dependency>

启动类 添加注解

@EnableEurekaServer //启用Eurek服务器功能

yml 配置文件

server: port: 5000 eureka: instance: hostname: localhost #注册中心的地址 client: register-with-eureka: false #不把自己注册到注册中心,自己本身就是 fetch-registry: false #不需要从注册中行取回信息 service-url: #注册中心地址 , 客户端访问注册中心时使用 defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

2.Feign (提供业务接口)

建议使用boot 项目

openfeign 提供远程业务接口

导入依赖

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>2.2.2.RELEASE</version> </dependency>

编写远程业务接口

调用者:

//远程调用的接口方法 //要求 方法完全一致 (修饰符,参数,方法名,返回值) //请求方式 ,请求路径完全一致 //使用的注解完全一致 import com.sl.commons.pojo.Employee; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; // 表示当前接口和一个 provider的服务对应 @FeignClient("provider") public interface EmployeeRemoteService { //远程调用的接口方法 //要求 方法完全一致 (修饰符,参数,方法名,返回值) //请求方式 ,请求路径完全一致 //使用的注解完全一致 @RequestMapping("/provider/get/employee/remote") public Employee getEmployeeRemote(); }

3.服务提供者

创建boot 项目 (web)

1.导入依赖

<!--依赖接口提供者工程--> <dependency> <groupId>com.sl</groupId> <artifactId>commons</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <!--客户端依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>2.2.2.RELEASE</version> </dependency>

yml配置

server: port: 1000 eureka: client: service-url: defaultZone: http://localhost:5000/eureka/ spring: application: name: provider

启动类 2.0版本之下的需要添加注解 其下任意一个即可

@EnableEurekaClient

只能是获取 Eureka注册中心提供的服务;

@EnableDiscoveryClient

可以获取任意注册中写 的服务

实现Feign提供的业务接口

注意点:

//远程调用的接口方法 //要求 方法完全一致 (修饰符,参数,方法名,返回值) //请求方式 ,请求路径完全一致 //使用的注解完全一致

@RestController public class EmployeeController { @RequestMapping("/provider/get/employee/remote") public Employee getEmployeeRemote(){ System.out.println("1000"); return new Employee(555,"provider:",555.55); }

4.服务消费者

创建 boot项目 (web)

导入依赖

<!--依赖接口提供者工程--> <dependency> <groupId>com.sl</groupId> <artifactId>commons</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <!--服务消费者依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> <version>2.2.2.RELEASE</version> </dependency> <!--客户端依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>2.2.2.RELEASE</version> </dependency>

yml配置

server: port: 4000 spring: application: name: cosumer eureka: client: service-url: defaultZone: http://localhost:5000/eureka/

启动类添加注解

扫描Feign提供的远程接口

@EnableFeignClients("com.sl.commons")

远程调用微服务接口

@RestController public class HumanResourcrHandler { //准备 远程调用微服务的接口 @Autowired private EmployeeRemoteService employeeRemoteService; @RequestMapping("/feign/get/employee") public Employee getEmployee() { return employeeRemoteService.getEmployeeRemote(); } @RequestMapping("/s") public String s() { return "ssss"; } }

小拓展

ribbon

负载均衡:的实现过程被隐藏 在远程调用微服务是开启;

spring-cloud-starter-netflix-ribbon

集群:一模一样的业务的集合,来自于同一个注册中兴,端口不一样,服务名一样;

参数的传递

基本类型

@RequestParam(“id”) String id

复杂类型

@RequestBody Student stu

服务雪崩

在微服务架构体系下,服务间的调用错综复杂,交织成一张大网。 如果其中某个节点突然无法正常工作,则访问它的众多服务都会被卡住,进而有更多服务被卡住,系统中的线程、CPU、内存等资源有可能被迅速耗尽,最终整个服务体系崩溃。 我们管这样的现象叫服务雪崩。

Hytrix介绍

Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里, 许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix 能够保正在个依 赖出问题的情况下,不会导致整体服务失败,避免级联故险,以提商分布式系统的弹性。 “断路器”本身是种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),面不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用用方的线程不会被长时间、不必要地占用,从而避见了故障在分布式系统中的蔓延。乃至雪崩: Hytrix能够提供眼务降级、服务熔断、服务用流、按近实时的监控等方面的功能。

服务熔断机制

[熔断机制]是应对雪蹦效应的一种微服务链路保护机制。 当扇出链路的某个微服务不可用或者响应时何太长时。会进行服务的[降级]:近而熔断该节点服务的调用,快速响应错误信息:当检测到该节点微服务调用响施正常后恢复调用链路,在SpringCloud框架里熔断机制通过Hystrix 实现。Hystrix 会监控微厦务间调用的状况,当失败的调用到一定阀值,缺省是5秒内20次调用夫败就会启动熔断机制。熔断机制的注解是@HystrixCommand.

服务消费者 备用方案 : 降级

服务降级 处理是在 客户端(Consumer) 实现完成的 , 于服务端(Provider)没有关系,当某个Consumer访问Provider却迟迟得不到响应时执行预先设定好的一个解决方案; 而不是一直等待 Consumer -------> 正常方案 : XXX --------------> provider | 异常 ↓ 备用方案 : XXX <-------------- 启用备选方案 | ↓ 返回相同类型的数据 让整个系统可以据需运行

在 业务接口 导入依赖

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> <version>2.2.2.RELEASE</version> </dependency>

自定义返回值类

作为项目的统一返回值

ResultEntity

package com.sl.commons.util; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * 项目统一使用 这个类型作为Ajax 请求 或远程 * 方法条用返回响应的数据格式 * @param <T> */ @Data @AllArgsConstructor @NoArgsConstructor public class ResultEntity<T> { public static final String SUCCESS = "SUCCESS"; //成功 public static final String FAILED = "FAILED"; //失败 public static final String NO_MESSAGE = "NO_MESSAGE"; //无消息 public static final String NO_DATA = "NO_DATA"; //无数据 private String resulr; private String message; private T data; /** * 操作成功,无需返回数据 * @return */ public static ResultEntity<String> successWithoutData(){ return new ResultEntity<String>(SUCCESS,NO_MESSAGE,NO_DATA); } /** * 操作成功 ,需要返回数据 * @param data * @param <E> * @return */ public static <E> ResultEntity<E> successWithoutData(E data){ return new ResultEntity<>(SUCCESS,NO_MESSAGE,data); } /** * 操作失败 ,返回错误信息 * @param message * @param <E> * @return */ public static <E> ResultEntity<E> failed(String message){ return new ResultEntity<>(SUCCESS,message,null); } }

创建 MyFallBackFactiry

实现 FallbackFactory

package com.sl.commons.factory; import com.sl.commons.api.EmployeeRemoteService; import com.sl.commons.pojo.Employee; import com.sl.commons.util.ResultEntity; import feign.hystrix.FallbackFactory; import org.springframework.stereotype.Component; import java.util.List; /** * 实现 Conumer 服务降级的功能 * 实现 FallbackFactory 这个借口是 要传入 @FeignClient注解标记的接口类型; * 实现create 方法 返回 @FeignClient注解标记的接口类型的对象 当 provide调用失败时 会执行这个对象对应的方法 */ @Component public class MyFallBackFactiry implements FallbackFactory<EmployeeRemoteService> { @Override public EmployeeRemoteService create(Throwable throwable) { return new EmployeeRemoteService() { @Override public Employee getEmployeeRemote() { return null; } @Override public List<Employee> getEList(String key) { return null; } @Override public ResultEntity<Employee> breaker(String signal) { return ResultEntity.failed(throwable.getMessage()+"降级使用"); } }; } }

接口业务类

注解

@FeignClient(value = “provider”,fallbackFactory = MyFallBackFactiry.class)

package com.sl.commons.api; import com.sl.commons.factory.MyFallBackFactiry; import com.sl.commons.pojo.Employee; import com.sl.commons.util.ResultEntity; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import java.util.List; // 表示当前接口和一个 provider的服务对应 //fallbackFactory 指定 provider 不可使用时 提供备用的 工厂对象 @FeignClient(value = "provider",fallbackFactory = MyFallBackFactiry.class) public interface EmployeeRemoteService { //远程调用的接口方法 //要求 方法完全一致 (修饰符,参数,方法名,返回值) //请求方式 ,请求路径完全一致 //使用的注解完全一致 @RequestMapping("/provider/get/employee/remote") public Employee getEmployeeRemote(); @RequestMapping("/provider/get/empList/remote") List<Employee> getEList(@RequestParam("key") String key); @RequestMapping("/provider/get/emp/circuit/breaker") public ResultEntity<Employee> breaker(@RequestParam("signal") String signal)throws InterruptedException; }

服务消费者类 扫描接口业务的包;

@EnableFeignClients("com.sl.commons")@SpringBootApplication(scanBasePackages = {"com.sl.commons","com.sl.consumer"})

服务消费者 导入依赖

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> <version>2.2.2.RELEASE</version> </dependency>

配置文件

feign: hystrix: enabled: true

服务提供者 备用方案 : 熔断

服务提供者 导入 依赖

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> <version>2.2.2.RELEASE</version> </dependency>

为指定的方法添加 备用方法

@HystrixCommand 指定方法出现问题时调用备份方法

// @HystrixCommand 指定方法出现问题时调用备份方法; @HystrixCommand(fallbackMethod = "breaker2") @RequestMapping("/provider/get/emp/circuit/breaker") public ResultEntity<Employee> breaker(@RequestParam("signal") String signal) throws InterruptedException { if ("quick-bang".equals(signal)) { throw new RuntimeException(); } if ("slow-bang".equals(signal)) { Thread.sleep(5000); } return ResultEntity.successWithoutData(new Employee(555,"provider3",555.55)); } public ResultEntity<Employee> breaker2(@RequestParam("signal") String signal){ String message = "方法出现问题"+signal+"/n执行备用方法"; return ResultEntity.failed(message); }

监控 服务

在 服务提供者

provider工程中添加依赖

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>

配置yml添加

management: endpoints: web: exposure: include: hystrix.stream

创建一个 监控工程

导入依赖

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId> <version>2.2.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> <version>2.2.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>

启用仪表盘监控功能

@EnableHystrixDashboard

访问服务监控

http://localhost:9000/hystrix

完成一整套的服务 ;才能有该服务的监控;

http://localhost:8001/actuator/hystrix.stream

zuul网关

为什么 要 定义统一的入口

不同的微服务有不同的网络地址,而外部的客户端 可能需要调用多个服务的接口才能完成一个业务需求. 会存在一下不利因素 1.客户端胡多次请求不同的微服务,增加客户端的复杂性; 2.存在跨域请求,在一定场景下处理相对复杂; 3.认证复杂,每一个服务器都要独立认证; 4.难以重构,随着项目的迭代,可能需要重新划分微服务,如果客户端直接和微服务同行,那么重构会难以实施; 5.某些微服务可能使用了其他的协议,直接访问有一定困难 Zuul 包含了对请求打的路由和过滤两个最主要的功能; 其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础, 而过滤器功能则负责对请求的处理过程进行干预,是实现请求校验,服务聚合功能的基础; Zuul和Eureka进行整合,将Zuul自身注册为Eureka服务治理下的应用,同时从Eureka中或得其他微服务的信息,以及以后的访问微服务都是Zuul跳转后获得; 总的来说, Zuul提供了 代理, 路由 和 过滤 的功能 (别名) (避免暴露微服务的名字) 具体微服务 请求 ---- Zuul ---- 请求特征 --- 微服务名字 --- Eureka --- 具体微服务 具体微服务

创建 Zuul网关 代理

创建新的 Sprinboot项目

导入依赖

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>2.2.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> <version>2.2.2.RELEASE</version> </dependency>

启动Zuul 网关代理功能

@EnableZuulProxy

访问测试

http://localhost:9000/ consumer/feign/get/fallback

​ zuul网关 微服务名字 目标具体的微服务

yml 配置

spring: application: name: zuul eureka: client: service-url: defaultZone: http://localhost:5000/eureka/ server: port: 9999 #自定义路由 zuul: routes: employye: #自定义路由规则名称,在底层的结构式map的键 service-id: consumer #目标微服务名称 ,ZuulRoute类型的一个属性 path: /zuul-emp/** # 用来代替目标微服务的名称 /**表示多层 ignored-services: '*' # 忽略所有的微服务 名称 # ignored-services: # - consumer # 忽略指定指定微服务名称 prefix: /sl #给访问的路径添加统一 的前缀

配置为zuul ,从zuul 进入调用服务 必须按照 zuul 定义的规则来进行访问服务

http://localhost:9000/ sl/zuul-empfeign/get/fallback

Zuul过滤器

MyZuulFilter

package com.sl.zuul.config; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; @Component public class MyZuulFilter extends ZuulFilter { Logger logger = LoggerFactory.getLogger(MyZuulFilter.class); @Override public String filterType() { //返回当前过滤器的类型,并决定当前过滤器在什么时候执行 //pre 表示 在目标微服务之前执行 String filterType = "pre"; return filterType; } @Override public int filterOrder() { return 0; } //判断当前请求是否过滤 //如果过滤 执行 run方法 //不过滤 直接放行 //shouldFilter 返回 true 调用 run 方法 false 放行 @Override public boolean shouldFilter() { //获取 RequestContext 对象 //threadLocal; 本地化; // 你在上游通过threadLocal.set(T value) 存 // 你在下游 通过threadLocal.get() 方法取 ,因为是同一条河(同一线程)所以可以取; RequestContext currentContext = RequestContext.getCurrentContext(); //获取 Request 对象 HttpServletRequest request = currentContext.getRequest(); String signal = request.getParameter("signal"); return "hello".equals(signal); } @Override public Object run() throws ZuulException { logger.info("当前请求要过滤,执行了 run() 方法"); //当前实现会忽略这个返回值 , 所以返回null,不做特殊处理; return null; } }

SpringCloud小结

SpringBoot 和SpringCloud关系 SpringBoot是基础 SpringCloud要基于SpringBoot开发 SpringCloud 和Dubbo对比 核心: Dubbo底层基于RPC SpringCloud底层基于RestFul.也可以说是基于HTTP 其他区别: SpringCloud相对于Dubbo功能更全面 SpringCloud 是一个一站式解决方案 SpringCloud能够天然的基于Spring全家桶开发 开发业务功能相关程度 Eureka ★★★★★ Ribbon ★★★ Feign ★★★★★ Hystrix ★★★ Zuul ★★★★★
最新回复(0)