《深入理解springCloud与微服务》笔记

第一章 微服务介绍

1.3 微服务的不足

1.3.2 分布式事务

CAP 理论,即同时满足“一致性”“可用性”和“分区容错”是 件不可能的事。

  • Consistency :指数据的强一致性。如果写入某个数据成功,之后读取,读到的都是新写入的数据:如果写入失败,之后读取的都不是写入失败的数据。
  • Availability :指服务的可用性
  • Partition-tolerance :指分区容错

两阶段提交
第一阶段,service-account 发起一个分布式事务,交给事务协调器 TC 理,事务协调器TC 向所有参与的事务的节点发送处理事务操作的准备操作 所有的参与节点执行准备操作,将Undo Redo 信息写进日志,并向事务管理器返回准备操作是否成功。
第二阶段,事务管理器收集所有节点的准备操作是否成功,如果都成功,则通知所有的节点执行提交操作;如果有一个失败,则执行回滚操作。
在这里插入图片描述
两阶段提交,将事务分成两部分能够大大提高分布式事务成功的概率。如果在第一阶段都成功了,而执行第二阶段的某一个节点失败,仍然导致数据的不准确,这时一般需要人工去处理,这就是当初在第一步记录日志的原因。另外,如果分布式事务涉及的节点很多,某一个节点的网络出现异常会导致整个事务处于阻塞状态,大大降低数据库的性能。所以一般情况下,尽量少用分布式事务。

第二章 Spring Cloud 简介

2.1 微服务应该具备的功能

服务的注册和发现。
服务的负载均衡
服务的容错。
服务网关。
服务配置的统管理。
链路追踪。
实时日志。

2.1.3 服务的容错

为了解决分布式系统的雪崩效应,分布式系统引进了熔断器机制。当一个服务的处理用户请求的 失败次数在一定时间内小于设定的阀值时,熔断器处于关闭状态,服务正常;当服务处理用户请求的失败次数大于设定的阀值时,说明服务出现了故障,打开熔断器,这时所有的请求会执行快速失败,不执行业务逻辑。当处于打开状态的熔断器时,一段时间后会处于半打开状态,并执行一定数量的请求,剩余的请求会执行快速失败,若执行的请求失败了,则继续打开熔断器;若成功了,则将熔断器关闭。

第五章 服务注册和发现 Eureka

5.1 简介

与Zookeeper类似,Eureka是用于服务注册和发现的组件。

5.1.2 为什么选择 Eureka

Eureka是Spring Cloud 首选推荐的服务注册与发现组件 Spring Cloud 其他组件 可以无缝对接。

5.1.3 Eureka 的基本架构

  • Register Service :服务注册中心,它是一个 Eureka Server ,提供服务注册和发现的功能。
  • Provider Service :服务提供者,它是 Eureka Client ,提供服务
  • Consumer Service :服务消费者,它是 Eureka Cient ,消费服务
    服务消费的基本过程如下:首先前要 个服务注册中心 Eureka Server ,服务提供 ureka
    Client 向服务注册中心 Eureka Server 注册,将自己的信息(比如服务名和服务的 IP 地址等)
    通过REST API的形式提交给服务注册中心 Eureka Server 。同样 ,服务消费 Eureka Client
    向服务注册中心 Eureka Server 注册,同时服务消费者获取一份服务注册列表的信息 该列表
    包含了所有向脱务注册中心 Eureka Server 册的服务信息。获取服务注册列表信息之后,服
    务消费者就知道服务提供者的 IP 地址,可以通过Http远程调度来消费服务提供者的服务。

5.4 源码解析Eureka

5.4.1 Eureka 的一些概念

5.4.1.1 Registe 一一服务注册

当Eureka Client 向 Eureka Server 注册时 Eureka Client 提供自身的元数据,比如 IP 地址、端口、运行状况指标的 Url、主页地址等信息。

5.4.1.2 Renew一一服务续约

Eureka Client 在默认的情况下会每隔 30 秒发送一次心跳来进行服务续约。通过服务续约来告知 Eureka Server 该Eureka Client 仍然可用,没有出现故障。正常情况下,如果 Eureka Server 90 秒内没有收到 ureka Client 的心跳, Eureka Server 会将 Eureka Client 实例从注册列表中删除。注意:官网建议不要更改服务续约的间隔时间。

5.4.1.3 Fetch Registries一一获取服务注册列表信息

Eureka Client 从Eureka Server 获取服务注册表信息,井将其缓存在本地。 Eureka Client会使用服务注册列表信息查找其他服务的信息,从而进行远程调用。该注册列表信息定时(每
30 秒) 更新一次,每次返回注册列表信息可能与 Eureka Client 的缓存信息不同, Eureka Client 会自己处理这些信息。如呆由于某种原因导致注册列表信息不能及时匹配, Eureka Client 会重新获取整个注册表信息。 Eureka Server 缓存了所有的服务注册列表信息,并将整个注册列表以及每个应用程序 信息进行了压缩,压缩内容和没有压缩的内容完全相同。 Eureka Client和Eureka Server 可以使用 JSON XML 数据格式进行通信。在默认的情况下, Eureka ClientJSON 格式的方式来获取服务注册列表的信息。

5.4.1.4 Cancel-一服务下线

Eureka Client 在程序关闭时可以向 Eureka Server 发送下线请求。发送请求后,该客户端的
实例信息将从 ureka Server 的服务注册列表中删除。该下线请求不会自动完成,需要在程序
关闭时调用以下代码:

DiscoveryManager.getinstance().shutdownComponent();

5.4.1.5 Eviction一一服务剔除

在默认情况下,当 Eureka Client 90 秒没有向 Eureka Server 发送服务续约(即心跳〉时, Eureka Server 会将该服务实例从服务 册列表删除,即服务剔除。

5.4.2 Eureka 的高可用架构

Eureka 高可用架构中有两个角色 ,即 Eureka Server和Eureka Client。Eureka Client 又分为 Applicaton Service和Application Client 即服务提供者和服务消费者。每个区域有一个Eureka 集群,并且每个区域至少有一个Eureka Server 以处理区域故障,以防服务器瘫痪。
Eureka Client向Eureka Server注册, 将自己的客户端信息提交给 Eureka Server 然后,Eureka Client 通过向 Eureka Server 发送心跳 (每 30 次)来续约服务 如果某个客户端不能持续续约,那 Eureka Server断定该客户端不可用 该不可用的客户端将在大约 90 秒后从Eureka Serve 务注册列 中删除。 服务注册列表信息和服务续约信息会被复制到集群中的每个Eureka Serve 节点。来自任何区域的 Eureka Client 都可以获取整个系统的服务注册列表信息,
跟据这些注册列表信息, Application Client可以远程调用 Applicaton Service 来消费服务。
在这里插入图片描述

5.4.3 Register服务注册

服务注册,即 Eureka Client 向 Eureka Server 提交自己的服务信息 包括 IP 地址、 端口、Serviceld 等信息。如果Eureka Client 置文件中没有配置 Serviceld ,则默认为配置文件中配置的服务名 ,即${spring.application.name的值。

5.4.4 Renew 服务续约

服务续约和服务注册非常相似,通过前文中的分析可以知 ,服务注册在Eureka Client 程序启动之后开启,并同时开启服务续约的定时任务。
调用方法为 eureka-client-1.6.2.jar的DiscoveryClient 的类下有 renew()方法。
Eureka Client 发送续约心跳的时间参数和Eureka Server 在多长时间内没有收到心跳将实例剔除的时间参数配置:

eureka.instance.leaseRenewalIntervalInSeconds
eureka.instance.leaseExpirationDurationInSeconds

5.4.5 为什么 Eureka Client 获取服务实例这么慢

5.4.5.1 Eureka Client 注册延迟

Eureka Client 启动之后,不是立即向 Eureka Server 注册的,而是有一个延迟向服务端注册的时间。通过跟踪源码,可以发现默认的延迟时间为 40 秒。

5.4.5.2 Eureka Server 的响应缓存

Eureka Server 维护每 30 更新一次响应缓存,可通过更改配置 eureka.server.responseCacheUpdatelntervalMs 来修改。所以即使是刚刚注册的实例,也不会立即出现在服务注册列表中。

5.4.5.3 Eureka Client 缓存

Eureka Client 保留注册表信息的缓存。该缓存每 30 秒更新一次。因此,Eureka Client 刷新本地缓存并发现其他新注册的实例可能需要 30 秒。

5.4.5.4 LoadBalancer 缓存

Ribbon 的负载平衡器从本地的 Eureka Client 获取服务注册列表信息。 Ribbon 本身还维护了缓存,以避免每个请求都需要从 Eureka Client 获取服务注册列表。此缓存每 秒刷新一次(可由 ribbon.ServerListRefreshlnterval配置) ,所以可能至少需要 秒的时间才能使用新注册的实例。

综上因素,一个新注册的实例,默认延迟 40 秒向服务注册中心注册,所以不能马上被Eureka Server 发现。另外,刚注册的 Eureka Client 不能立即被其他服务调用,原因是调用方由于各种缓存没有及时获取到最新的服务注册列表信息。

5.4.6 Eureka 的自我保护模式

当有一个新的 Eureka Server 出现时,它尝试从相邻 Peer 节点获取所有服务实例注册表信息。如果从相邻 Peer节点获取信息时出现了故障 Eureka Server 会尝试其他的 Peer 节点。如果 Eureka Serve 能够成功获取所有的服务实例信息,则根据配置信息设置服务续约的阀值。在任何时间,如果 Eureka Serve 接收到的服务续约低于为该值配置的百分比(默认为 15 分钟内低于 85% ),则服务器开启自我保护模式,即不再剔除注册列表的信息
这样做的好处在于,如果是 Eureka Server 自身的网络问题而导致 Eureka Client 无法续约,Eureka Client 注册列表信息不再被删除,也就是 Eureka Client 还可以被其他服务消费。
在默认情况下, Eureka Server 的自我保护模式是开启的,如果需要关闭,则在配置文件添
加以下代码:

eureka:
	server: 
		enable-self-preservation : false

第六章 负载均衡 Ribbon /ˈrɪbən/

6.1 RestTemplate简介

RestTemplate 是Spring Resources 中一个访问 RESTful API 接口的网络请求框架。
RestTemplate 是用来消费 REST 服务的,所以 RestTemplate 的主要方法都与REST的http协议的一些方法紧密相连,例如 HEAD GET POST PUT DELETE OPTIONS 等方法,这些方法在 RestTemplate 类对应的方法为 headForHeaders()、 getForObject()、postForObject()、put()和 delete() 等。
举例说明,写一个RestTestController类,获取 https://www.baidu.com/ 的网页Html 代码。首先在RestTestController类上加@RestController 注解 ,开启RestController 功能。通过RestTemplate的getForObject()方法可以获取 https://www.baidu.com/ 的网页Html代码,并在API接口"/testRest"返回该网页的 Html 字符串。代码如下:

@RestController 
public class RestTestController { 
	@GetMapping ("/testRest") 
	public String testRest() { 
		RestTemplate restTemplate=new RestTemplate() ; 
		return restTemplate.getForObject("https://www.baidu.com/",String.class) ;
	}
}

6.2 Ribbon简介

常见的负载均衡有两种方式。一种是独立进程单元,通过负载均衡策略,将请求转发到不同的执行单元上,例如 Ngnix 。
另一种是将负载均衡逻辑以代码的形式封装到服务消费者的客户端上,服务消费者客户端维护了一份服务提供的信息列 ,有了信息列表,通过负载均衡策略将请求分摊给多个服务提供者,从而达到负载均衡的目的。
Ribbon 是Netflix(奈飞)公司开源的一个负载均衡的组件,它属于上述的第二种方式,是将负载均衡逻辑封装在客户端中,并且运行在客户端的进程里。

6.3 使用RestTemplate和Ribbon来消费服务

6.4 LoadBalancerClient 简介

负载均衡器的核心类为 LoadBalancerClient, LoadBalancerCiient 可以获取负载均衡的服务提供者的实例信息。
。在Spring Cloud 项目中,负载均衡器 Ribbon 会默认从 Eureka Client 的服务注册列表中获取服务的信息,并缓存一份。根据缓存的服务注册列表信息,可以通过 LoadBalancerClient 来选择不同的服务实例,从而实现负载均衡。如果禁止 Ribbon从Eureka获取注册列表信息,则需要自己去维护一份服务注册列表信息。 根据自己维护服务注册列表的信息, Ribbon也可以实现负载均衡。

6.5 源码解析Ribbon

Ribbon 负载均衡主要是通过LoadBalancerClient来实现的,而LoadBalancer-Client 具体交给了 ILoadBalancer 来处理, ILoadBalancer 通过配置IRule、IPing等,向 EurekaClient获取注册列表的信息,默认每10秒向EurekaClient发送一次"ping", 进而检查是否需要更新服务的注册列表信息。最后 ,在得到服务注册列表信息后, ILoadBalancer 根据IRule的策略进行负载均衡。
而RestTemplate 加上@LoadBalance注解后,在远程调度时能够负载均衡, 主要是维护了
个被@LoadBalance 注解的 RestTemplate 列表,并给该列表中 RestTemplate对象添加了
截器。在拦截器的方法中 ,将远程调度方法交给了 Ribbon 负载均衡器 LoadBalancerClient
,从而达到了负载均衡的目的。

第七章 声明式调用Feign

7.1 FeignClient详解

在这里插入图片描述

@Feign Client 注解用于创建声明式 API 接口,该接口是RESTful风格的。Feign被设计成插拔式的,可以注入其他组件和 Feign 起使用。最典型的是如果Ribbon可用,Feign会和Ribbon 结合进行负载均衡。
在代码中 value()和 name()样,是被调用的服务的Serviceld。url()直接填写硬编码的url地址 decode404()即 404 是被解码,还是抛异常。 configuration()指明 FeignClient 配置类,默认的配置类为 FeignClientsConfiguration类,在缺省的情况下,这个类注入了默认的 Decoder、Encoder和Contract 等配置的 Bean、fallback()为配置熔断器的处理类。

7.4 从源码角度讲解Feign的工作原理

Feign是一个伪Java Http客户端,Feign不做任何的请求处理。Feign通过处理注解生成Request模板,从而简化了Http API的开发。开发人员可以使用注解的方式定制Request API模板。在发送Http Request请求之前,Feign通过处理注解的方式替换掉Request模板中的参数,生成真正的Request,并交给Java Http客户端去处理。利用这种方式,开发者只需要关注Feign注解模板的开发,而不用关注Hp请求本身,简化了Hp请求的过程,使得Hp请求变得简单和容易理解。
Feign通过包扫描注入FeignClient的Bean,该源码在FeignClientsRegistrar类中。首先在程序启动时,会检查是否有@EnableFeignClients注解,如果有该注解,则开启包扫描,扫描被@FeignClient注解的接口。
当程序的启动类上有@EnableFeignClients注解。在程序启动后,程序会通过包扫描将有@FeignClient注解修饰的接口连同接口名和注解的信息一起取出,赋给BeanDefinitionBuilder,然后根据BeanDefinitionBuilder得到BeanDefinition,最后将BeanDefinition注入IoC容器中。
注入BeanDefinition之后,通过JDK的代理,当调用Feign Client接口里面的方法时,该方法会被拦截,源码在ReflectiveFeign类。
在SynchronousMethodHandler类进行拦截处理,会根据参数生成RequestTemplate对象,该对象是Http请求的模板。
在上述代码中,有一个executeAndDecode()方法,该方法通过RequestTemplate生成Request请求对象,然后用Http Client获取Response,即通过Http Client进行Htp请求来获取响应。

7.5 在Feign中使用HttpClient和OkHttp

在Feign中,Client是一个非常重要的组件,Feign最终发送Request请求以及接收Response响应都是由Client组件完成的。Client在Feign源码中是一个接口,在默认的情况下,Client的实现类是Client.Default,Client.Default是由HttpURLConnnection来实现网络请求的。另外,Client还支持HttpClient和OkhHttp来进行网络请求。
在工程 pom 文件加上 feign-httpclient 的依赖,Feign 就会采用HttpClient 作为网络请求框架,而不是默认的 HttpURLConnection 。代码如下:

<dependency> 
	<groupid>com.netflix.feign</groupid> 
	<artifactid>feign-httpclient</artifactid> 
	<version>RELEASE</ve rsion> 
</dependency>

同理,如果想要 Feign 中使用 Okhttp 作为网络请求框架,则只需要在 pom 文件上加上feign-okhttp 的依赖,代码如下:

<dependency> 
	<groupid>com.netflix.feign</groupid> 
	<artifactid>feign-okhttp</artifactid> 
	<version>RELEASE</ve rsion> 
</dependency>

7.7 总结

总的来说,Feign的源码实现过程如下。
(1)首先通过@EnableFeignClients注解开启FeignClient的功能。只有这个注解存在,才会在程序启动时开启对@FeignClient注解的包扫描。
(2)根据Feign的规则实现接口,并在接口上面加上@FeignClient注解。
(3)程序启动后,会进行包扫描,扫描所有的@FeignClient的注解的类,并将这些信息注入IoC容器中。
(4)当接口的方法被调用时,通过JDK的代理来生成具体的RequestTemplate模板对象。
(S)根据RequestTemplate再生成Http请求的Request对象。
(6)Request对象交给Client去处理,其中Client的网络请求框架可以是HttpURLConnection、HttpClient和OkHttp。
(7)最后Client被封装到LoadBalanceClient类,这个类结合类Ribbon做到了负载均衡。

第8章 熔断器 Hystrix [hɪst’rɪks]

8.1 什么是Hystrix

Hystrix是Netflix公司开源的一个项目,它提供了熔断器功能,能够阻止分布式系统中出现联动故障。Hystriⅸ是通过隔离服务的访问点阻止联动故障的,并提供了故障的解决方案,从而提高了整个分布式系统
的弹性。

8.2 Hystrix解决了什么问题

某个服务的单个点的请求故障会导致用户的请求处于阻塞状态,最终的结果就是整个服务的线程资源消耗殆尽。由于服务的依赖性,会导致依赖于该故障服务的其他服务也处于线程阻塞状态,最终导致这些服务的线程资源消耗殆尽,直到不可用,从而导致整个问服务系统都不可用,即雪崩效应。
为了防止雪崩效应,因而产生了熔断器模型。Hystrix是在业界表现非常好的一个熔断器模型实现的开源组件,它是Spring Cloud组件不可缺少的一部分。

8.3 Hystrix的设计原则

总的来说,Hystrix的设计原则如下。

  • 防止单个服务的故障耗尽整个服务的Servlet容器(例如Tomcat)的线程资源。
  • 快速失败机制,如果某个服务出现了故障,则调用该服务的请求快速失败,而不是线程等待。
  • 提供回退(fallback)方案,在请求发生故障时,提供设定好的回退方案。
  • 使用熔断机制,防止故障扩散到其他服务。
  • 提供熔断器的监控组件Hystrix Dashboard,可以实时监控熔断器的状态。

8.4 Hystrix的工作机制

首先,当服务的某个API接口的失败次数在一定时间内小于设定的阀值时,熔断器处于关闭状态,该API接口正常提供服务。当该API接口处理请求的失败次数大于设定的阀值时,Hystrix判定该API接口出现了故障,打开熔断器,这时请求该API接口会执行快速失败的逻辑(即fallback回退的逻辑),不执行业务逻辑,请求的线程不会处于阻塞状态。处于打开状态的熔断器,一段时间后会处于半打开状态,并将一定数量的请求执行正常逻辑。剩余的请求会执行快速失败,若执行正常逻辑的请求失败了,则熔断器继续打开;若成功了,则将熔断器关闭。这样熔断器就具有了自我修复的能力。

8.5 在RestTemplate和Ribbon上使用熔断器

首先在工程的pom文件中引用Hystrix的起步依赖spring-cloud-starter-hystrix,代码如下:

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>

然后在Spring Boot的启动类EurekaRibbonClientApplication加上@EnableHystrix注解开启Hystrix的熔断器功能,代码如下:

@SpringBootApplication
@EnableEurekaclient
@EnableHystrix
public class EurekaRibbonclientApplication{
	public static void main(String[]args){
		SpringApplication.run(EurekaRibbonclientApplication.class,args);
	}
}

修改RibbonService的代码,在hiO方法上加@ystrixCommand注解。有了@HystrixCommand注解,hi()方法就启用Hystrix熔断器的功能,其中,fallbackMethod为处理回退(fallback)逻辑的方法。在本例中,直接返回了一个字符串。在熔断器打开的状态下,会执行fallback逻辑。

@Service
public class RibbonService{
	@Autowired
	RestTemplate restTemplate;
	@HystrixCommand (fallbackMethod "hiError")
	public String hi(String name){
		return restTemplate.getForobject("http://eureka-client/hi?name="+name,String.class);
	public String hiError(String name){
		return "hi,"+name+",sorry,error!"
	}
}

8.6 在Feign上使用熔断器

由于Feign的起步依赖中已经引入了Hystrix的依赖,所以在Feign中使用Hystrix不需要引入任何的依赖。只需要在eureka-feign-client工程的配置文件application.yml中配置开启Hystrix的功能,配置文件application.yml中加以下配置:

feign:
	hystrix:
		enabled:true

然后修改eureka-feign-client工程中的EurekaClientFeign代码,在@FeignClient注解的fallback配置加上快速失败的处理类。该处理类是作为Feign熔断器的逻辑处理类,必须实现被@FeignClient修饰的接口。例如案例中的HiHystrix类实现了接口EurekaClientFeign,最后需要以Spring Bean的形式注入IoC容器中。代码如下:

@Feignclient (value "eureka-client",
configuration FeignConfig.class,fallback HiHystrix.class)
public interface EurekaclientFeign {
	@GetMapping(value ="/hi")
	String sayHiFromclientEureka (@RequestParam(value "name") String name);
}

HiHystrix作为熔断器的逻辑处理类,需要实现EurekaClientFeign接口,并需要在接口方法sayHiFromClientEureka()里写处理熔断的具体逻辑,同时还需要在HiHystrix类上加@Component注解,注入IoC容器中。代码如下:

@Component
public class HiHystrix implements EurekaclientFeign{
	@Override
	public String sayHiFromclientEureka(String name){
		return "hi,"+name+",sorry,error!"
	}
}

第9章 路由网关Sping Cloud Zuul

9.2 Zuul的工作原理

Zuul是通过Servlet来实现的,Zuul通过自定义的ZuulServlet(类似于Spring MVC的DispatcServlet)来对请求进行控制。Zuul的核心是一系列过滤器,可以在Htp请求的发起和响应返回期间执行一系列的过滤器。Zuul包括以下4种过滤器。

  • PE过滤器:它是在请求路由到具体的服务之前执行的,这种类型的过滤器可以做安全验证,例如身份验证、参数验证等。
  • ROUTING过滤器:它用于将请求路由到具体的微服务实例。在默认情况下,它使用Http Client进行网络请求。
  • POST过滤器:它是在请求已被路由到微服务后执行的。一般情况下,用作收集统计信息、指标,以及将响应传输到客户端。
  • ERROR过滤器:它是在其他过滤器发生错误时执行的。
    Zul采取了动态读取、编译和运行这些过滤器。过滤器之间不能直接相互通信,而是通过RequestContext对象来共享数据,每个请求都会创建一个RequestContext对象。Zuul过滤器具有以下关键特性。
  • Type(类型):Zuul过滤器的类型,这个类型决定了过滤器在请求的哪个阶段起作用,例如Pre、Post阶段等。
  • Execution Order(执行顺序):规定了过滤器的执行顺序,Order的值越小,越先执行。
  • Criteria(标准):Filter执行所需的条件。
  • Action(行动):如果符合执行条件,则执行Action(即逻辑代码)。
    当一个客户端Request请求进入Zuul网关服务时,网关先进入“pre filter’”,进行一系列的验证、操作或者判断。然后交给“routing filter”进行路由转发,转发到具体的服务实例进行逻辑处理、返回数据。当具体的服务处理完后,最后由“post filter’”进行处理,该类型的处理器处理完之后,将Response信息返回给客户端。
    ZuulServlet是Zuul的核心Servlet。ZuulServlet的作用是初始化ZuulFilter,并编排这些ZuulFilter的执行顺序。该类中有一个service()方法,执行了过滤器执行的逻辑。
    首先执行preRoute()方法,这个方法执行的是PRE类型的过滤器的逻辑。如果执行这个方法时出错了,那么会执行error(e)和postRoute()。然后执行route()方法,该方法是执行ROUTING类型过滤器的逻辑。最后执行postRoute(),该方法执行了POST类型过滤器的逻辑。
    在这里插入图片描述

9.3 案例实战

9.3.1 搭建Zuul服务

在pom文件中引入相关依赖,包括继承了主Maven工程的pom文件,引入Eureka Client的起步依赖spring-cloud-starter-eureka、Zuul的起步依赖spring-cloud-starter–zuul、Web功能的起步依赖spring-.boot-starter-web,以及Spring Boot测试的起步依赖spring-boot-starter-test

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<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>
	<scope>test</scope>
</dependency>

在程序的启动类EurekaZuulClientApplication加上@EnableEurekaClient注解,开启EurekaClient的功能;加上@SpringBootApplication注解,表明自己是一个Spring Boot工程;加上@EnableZuulProxy注解,开启Zuul的功能。代码如下:

@EnableZuulProxy
@EnableEurekaclient
@SpringBootApplication
public class EurekaZuulclientApplication{
	public static void main(String[] args){
		SpringApplication.run (EurekaZuulclientApplication.class,args);
	}
}

9.3.2在Zuul上配置API接口的版本号

如果想给每一个服务的API接口加前缀,例如http://localhost:5000 vI/hiapi/hi?name-forezp/,即在所有的API接口上加一个vl作为版本号。这时需要用到zuul.prefix的配置,配置示例代码如下:

zuul:
	routes:
		hiapi:
			path:/hiapi/**
			serviceId:eureka-client
		ribbonapi:
			path:/ribbonapi/**
			serviceId:eureka-ribbon-client
		feignapi:
			path:/feignapi/**
			serviceId:eureka-feign-client
	zuul.prefix:/v1

9.3.3在Zuu上配置熔断器

Zuul作为Netflix组件,可以与Ribbon、Eureka和Hystrix等组件相结合,实现负载均衡、熔断器的功能。在默认情况下,Zuul和Ribbon相结合,实现了负载均衡的功能。下面来讲解如何在Zuul上实现熔断功能。
在Zuul中实现熔断功能需要实现ZuulFallbackProvider的接口。实现该接口有两个方法,一个
是getRoute()方法,用于指定熔断功能应用于哪些路由的服务;另一个方法fallbackResponse()为进
入熔断功能时执行的逻辑。ZuulFallbackProvider的源码如下:

public interface ZuulFallbackProvider{
	public String getRoute();
	public clientHttpResponse fallbackResponse();
}

9.3.4 在Zuul中使用过滤器

实现过滤器很简单,只需要继承ZuulFilter,并实现ZuulFilter中的抽象方法,包括filterType()和filterOrder(),以及IZuulFilter的shouldFilter()和Object run()的两个方法。其中,filterType()即过滤器的类型,在前文已经讲解过了,它有4种类型,分别是“pre”“post”“routing”和“error”。filterOrder()是过滤顺序,它为一个Int类型的值,值越小,越早执行该过滤器。shouldFilter()表示该过滤器是否过滤逻辑,如果为true,则执行run()方法;如果为false,则不执行run()方法。run()方法写具体的过滤的逻辑。

9.3.5 Zuul的常见使用方式

Zuul是采用了类似于Spring MVC的DispatchServlet来实现的,采用的是异步阻塞模型,所以性能比Ngnix差。由于Zuul和其他Netflix组件可以相互配合、无缝集成,Zuul很容易就能实现负载均衡、智能路由和熔断器等功能。在大多数情况下,Zuul都是以集群的形式存在的。由于Zuul的横向扩展能力非常好,所以当负载过高时,可以通过添加实例来解决性能瓶颈。
一种常见的使用方式是对不同的渠道使用不同的Zuul来进行路由,例如移动端共用一个Zuul网关实例,Wb端用另一个Zuul网关实例,其他的客户端用另外一个Zuul实例进行路由。这种不同的渠道用不同Zuul实例的架构如图9-3所示。
在这里插入图片描述

另外一种常见的集群是通过Ngnix和Zuul相互结合来做负载均衡。暴露在最外面的是Ngnix主从双热备进行Keepalive,Ngnix经过某种路由策略,将请求路由转发到Zuul集群上,Zuul最终将请求分发到具体的服务上。架构图如图9-4所示。
在这里插入图片描述

第10章 配置中心Spring Cloud Config

10.1 Config Server从本地读取配置文件

Config Server可以从本地仓库读取配置文件,也可以从远处Git仓库读取。本地仓库是指将所有的配置文件统一写在Config Server工程目录下,Config Sever暴露Http API接口,ConfigClient通过调用Config Sever的Http API接口来读取配置文件。

10.2 Config Server从远程Git仓库读取配置文件

Spring Cloud Config支持从远程Git仓库读取配置文件,即Config Server可以不从本地的仓库读取,而是从远程Git仓库读取。这样做的好处就是将配置统一管理,并且可以通过Spring Cloud Bus在不人工启动程序的情况下对Config Client的配置进行刷新。本例采用GitHub作为远程Git仓库。

10.3 构建高可用的Config Server

当服务实例很多时,所有的服务实例需要同时从配置中心Config Server读取配置文件,这时可以考虑将配置中心Config Server做成一个微服务,并且将其集群化,从而达到高可用。配置中心Config Server高可用的架构图如图10-1所示。ConfigServer和Config Client向Eureka Server注册,且将Config Server多实例集群部署。

10.4 使用Spring Cloud Bus刷新配置

Spring Cloud Bus是用轻量的消息代理将分布式的节点连接起来,可以用于广播配置文件的更改或者服务的监控管理。一个关键的思想就是,消息总线可以为微服务做监控,也可以实现应用程序之间相互通信。Spring Cloud Bus可选的消息代理组建包括RabbitMQ、AMQP和Kafka等。

第11章 服务链路追踪Spring Cloud Sleuth

Spring Cloud Sleuth是Spring Cloud的一个组件,它的主要功能是在分布式系统中提供服务链路追踪的解决方案。
目前,常见的链路追踪组件有Google的Dapper、Twitter的Zipkin,以及阿里的Eagleeye(鹰眼)等,它们都是非常优秀的链路追踪开源组件。
本章主要讲述如何在Spring Cloud Sleuth中集成Zipkin。在Spring Cloud Sleuth中集成Zipkin非常简单,只需要引入相应的依赖并做相关的配置即可。

11.2 基本术语

Spring Cloud Sleuth采用了Google的开源项目Dapper的专业术语。
(1)Span:基本工作单元,发送一个远程调度任务就会产生一个Span,Span是用一个64位ID唯一标识的,Trace是用另一个64位ID唯一标识的。Span还包含了其他的信息,例如摘要、时间戳事件、Span的ID以及进程ID。
(2)Trace:由一系列Span组成的,呈树状结构。请求一个微服务系统的API接口,这个API接口需要调用多个微服务单元,调用每个微服务单元都会产生一个新的Span,所有由这个请求产生的Span组成了这个Trace。
(3)Annotation:用于记录一个事件,一些核心注解用于定义一个请求的开始和结束,这些注解如下。

  • cs-Client Sent:客户端发送一个请求,这个注解描述了Span的开始。
  • sr-Server Received:服务端获得请求并准备开始处理它,如果将其sr减去cs时间戳,便可得到网络传输的时间。
  • ss-Server Sent:服务端发送响应,该注解表明请求处理的完成(当请求返回客户端),用ss的时间戳减去sr时间戳,便可以得到服务器请求的时间。
  • cr-Client Received:客户端接收响应,此时Span结束,如果cr的时间戳减去cs时间戳,便可以得到整个请求所消耗的时间。

第12章 微服务监控Spring Boot Admin

Spring Boot Admin用于管理和监控一个或者多个Spring Boot程序。Spring Boot Admin分为Server端和Client端,Client端可以通过Htp向Server端注册,也可以结合Spring Cloud的服务注册组件Eureka进行注册。Spring Boot Admin提供了用AngularJs编写的UI界面,用于管理和监控。其中监控内容包括Spring Boot的监控组件Actuator的各个Htp节点,也支持更高级的功能,包括Turbine、Jmx、Loglevel等。

12.2 在Spring Boot Admin中集成Turbine

Hystrix Dashboard是一个监控熔断器状况的组件,而Turbine是一个可以聚合多个Hystrix Dashboard的组件。在Spring Boot Admin中,可以很方便地集成Turbine组件。集成Turbine组件非常简单,只需要引入相关的依赖并做简单的配置即可。

第l3章Spring Boot Security详解

13.1 Spring Security简介

13.1.1 什么是Spring Security

Spring Security是Spring Resource社区的一个安全组件,Spring Security为JavaEE企业级开发提供了全面的安全防护。Spring Security采用“安全层”的概念,使每一层都尽可能安全,连续的安全层可以达到全面的防护。Spring Security可以在Controller层、Service层、DAO层等以加注解的方式来保护应用程序的安全。Spring Security提供了细粒度的权限控制,可以精细到每一个API接口、每一个业务的方法,或者每一个操作数据库的DAO层的方法。Spring Security提供的是应用程序层的安全解决方案,一个系统的安全还需要考虑传输层和系统层的安全,例如采用Htpps协议、服务器部署防火墙等。

13.1.2 为什么选择Spring Security

使用Spring Security有很多原因,其中一个重要原因是它对环境的无依赖性、低代码耦合性。将工程重新部署到一个新的服务器上,不需要为Spring Security做什么工作。Spring Security提供了数十个安全模块,模块与模块间的耦合性低,模块之间可以自由组合来实现特定需求的安全功能,具有较高的可定制性。总而言之,Spring Security具有很好的可复用性和可定制性。
在安全方面,有两个主要的领域,一是“认证”,即你是谁;二是“授权”,即你拥有什么权限,Spring Security的主要目标就是在这两个领域。“认证”是认证主体的过程,通常是指可以在应用程序中执行操作的用户、设备或其他系统。“授权”是指决定是否允许已认证的主体执行某一项操作。
安全框架多种多样,那为什么选择Spring Security作为微服务开发的安全框架呢?JavaEE有另一个优秀的安全框架Apache Shiro,Apache Shiro在企业级的项目开发中十分受欢迎,一般使用在单体服务中。但在微服务架构中,目前版本的Apache Shiro是无能为力的。
Spring Security来自Spring Resource社区,采用了注解的方式控制权限,熟悉Spring的开发者很容易上手Spring Security。另外一个原因就是Spring Security易于应用于Spring Boot工程,也易于集成到采用Spring Cloud构建的微服务系统中。

13.1.3 Spring Security提供的安全模块

在安全验证方面,Spring Security提供了很多的安全验证模块。大部分的验证模块来自第三方的权威机构或者一些相关的标准制定组织,Spring Security自身也提供了一些验证模型。

13.2 Spring Boot Security与Spring Security的关系

在Spring Security框架中,主要包含了两个依赖Jar,分别是spring-security-.web依赖和spring-security-config依赖,代码如下:

    <dependencies>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>4.2.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>4.2.2.RELEASE</version>
        </dependency>
    </dependencies>

Spring Boot对Spring Security框架做了封装,仅仅是封装,并没有改动Spring Security这两个包的内容,并加上了Spring Boot的起步依赖的特性。spring-boot-starter-security依赖如下:

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

进入spring-boot-starter-security的pom文件,可以发现pom文件包含了Spring Security的两个Jar包,并移除了这两个Jar包的apo功能,引入了aop的依赖,另外包含了spring-boot-starter的依赖。由此可见,spring-boot-starter-security是对Spring Security的一个封装。

13.4 总结

使用Spring Security还是比较简单的,没有想象中那么复杂。首先引入Spring Security相关的依赖,然后写一个配置类,该配置类继承了WebSecurityConfigurerAdapter,并在该配置类上加@EnableWebSecurity注解开启Web Security。再需要配置AuthenticationManagerBuilder,AuthenticationManagerBuilder配置了读取用户的认证信息的方式,可以从内存中读取,也可以从数据库中读取,或者用其他的方式。其次,需要配置HttpSecurity,HttpSecurity配置了请求的认证规则,即哪些UI请求需要认证、哪些不需要,以及需要拥有什么权限才能访问。最后,如果需要开启方法级别的安全配置,需要通过在配置类上加@EnableGlobalMethodSecurity注解开启,方法级别上的安全控制支持secureEnabled、jsr250 Enabled和prePostEnabled这3种方式,用的最多的是prePostEnabled。其中,prePostEnabled包括PreAuthorize和PostAuthorize两种形式,一般只用到PreAuthorize这种方式。Spring Security的思维导图如图l3-8所示。
在这里插入图片描述

第14章 使用Spring Cloud OAuth2保护微服务系统

14.1 什么是OAuth2

OAuth2 是一个标准的授权协议。OAuth2允许不同的客户端通过认证和授权的形式来访问被其保护起来的资源。在认证和授权的过程中,主要包含以下3种角色。

  • 服务提供方Authorization Server。
  • 资源持有者Resource Server。
  • 客户端Client。
    OAuth2的认证流程如图14-1所示,具体如下。
    (1)用户(资源持有者)打开客户端,客户端询问用户授权。
    (2)用户同意授权。
    (3)客户端向授权服务器申请授权。
    (4)授权服务器对客户端进行认证,也包括用户信息的认证,认证成功后授权给予令牌。
    在这里插入图片描述

14.2 如何使用Spring OAuth2

OAuth2协议在Spring Resources中的实现为Spring OAuth2。Spring OAuth2分为两部分,分别是OAuth22 Provider和OAuth2 Client,下面来对二者逐一讲解。

14.2.1 OAuth2 Provider

OAuth2 Provider负责公开被OAuth2保护起来的资源。OAuth2 Provider需要配置代表用户的OAuth2客户端信息,被用户允许的客户端就可以访问被OAuth2保护的资源。OAuth2 Provider通过管理和验证OAuth2令牌来控制客户端是否有权限访问被其保护的资源。另外,Oauth2 Provider还必须为用户提供认证API接口。根据认证API接口,用户提供账号和密码等信息,来确认客户端是否可以被OAuth2 Provider授权。这样做的好处就是第三方客户端不需要获取用户的账号和密码,通过授权的方式就可以访问被OAuh2保护起来的资源。
OAuth2 Provider的角色被分为Authorization Service(授权服务)和Resource Service(资源服务),通常它们不在同一个服务中,可能一个Authorization Service对应多个Resource Service。.Spring OAuth2需配合Spring Security一起使用,所有的请求由Spring MVC控制器处理,并经过一系列的Spring Security过滤器。
在Spring Security过滤器链中有以下两个节点,这两个节点是向Authorization Service获取验证和授权的。

  • 授权节点:默认为/oauth/.authorize。
  • 获取Token节点:默认为/oauth/token。
1.Authorization Server配置

在配置Authorization Server时,需要考虑客户端(Client)从用户获取访问令牌的授权类型(例如授权代码、用户凭据、刷新令牌)。Authorization Server需要配置客户端的详细信息和令牌服务的实现。
在任何实现了AuthorizationServerConfigurer接口的类上加@EnableAuthorizationServer注解,开启Authorization Server的功能,以Bean的形式注入Spring IoC容器中,并需要实现以下3个配置。

  • ClientDetailsServiceConfigurer:配置客户端信息。
  • AuthorizationServerEndpointsConfigurer:配置授权Token的节点和Token服务。
  • AuthorizationServerSecurityConfigurer:配置Token节点的安全策略。

下面来具体讲解这3个配置。
(1)ClientDetailsServiceConfigurer
客户端的配置信息既可以放在内存中,也可以放在数据库中,需要配置以下信息。

  • clientId:客户端Id,需要在Authorization Server中是唯一的。
  • secret:客户端的密码。
  • scope:客户端的域。
  • authorizedGrantTypes:认证类型。
  • authorities:权限信息。
    (2)AuthorizationServerEndpointsConfigurer
    在默认情况下,AuthorizationServerEndpointsConfigurer配置开启了所有的验证类型,除了密码类型的验证,密码验证只有配置了authenticationManager的配置才会开启。AuthorizationServerEndpointsConfigurer配置由以下5项组成。
  • authenticationManager:只有配置了该选项,密码认证才会开启。在大多数情况下都是密码验证,所以一般都会配置这个选项。
  • userDetailsService:配置获取用户认证信息的接口,和上一章实现的userDetailsService类似。
  • authorizationCodeServices:配置验证码服务。
  • implicitGrantService:配置管理implict验证的状态。
  • tokenGranter:配置Token Granter。

另外,需要设置Token的管理策略,目前支持以下3种。

  • InMemoryTokenStore:Token存储在内存中。
  • JdbeTokenStore:Token存储在数据库中。需要引入spring-.jdbc的依赖包,并配置数据源,以及初始化Spring OAuth2的数据库脚本,即上一节的数据库脚本。
  • JwtTokenStore::采用JWT形式,这种形式没有做任何的存储,因为JWT本身包含了用户验证的所有信息,不需要存储。采用这种形式,需要引入spring-jwt的依赖。
    (3)AuthorizationServerSecurityConfigurer
    如果资源服务和授权服务是在同一个服务中,用默认的配置即可,不需要做其他任何的配置。但是如果资源服务和授权服务不在同一个服务中,则需要做一些额外配置。如果采用RemoteTokenServices(远程Token校验),资源服务器的每次请求所携带的Token都需要从授权服务做校验。这时需要配置“/oauth/.check token”校验节点的校验策略。
    Authorization Server的配置比较复杂,细节较多,Authorization Server的配置思维导图如图14-2所示。通过在实现了AuthorizationServerConfigurer接口的类上加@EnableAuthorizationServer注解,开启AuthorizationServer的功能,并注入IoC容器中,然后需要配置ClientDetailsServiceConfigurer、AuthorizationServerSecurityConfigurer和AuthorizationServerEndpointsConfigurer,它们有很多可选的配置,需要读者慢慢理解。
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/455813.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

百度云加速即将下线

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 松松商城作为多年百度云加速代理商&#xff0c;上周接到通知&#xff1a;百度云加速产品计划于2024年4月30日下线&#xff0c;目前也无法做实名了。 同时&#xff0c;百度云加速也开始逐步迁移到百度云&#xff0…

【Sql】MVCC有关问题,以及锁,日志和主从复制原理

目录 MVCC 解决什么问题? 实现原理 隐式字段 undo log Read View(读视图) InnoDB 对 MVCC 的实现 锁 分类 锁升级&#xff1f; InnoDB 的行锁&#xff1f; 死锁避免&#xff1f; 乐观锁和悲观锁 日志 主从复制原理 主从复制的作用 MySQL主从复制解决的问题 涉…

Java基于微信小程序的校园生活互助小助手

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

vue3 el-form中嵌套el-tabale 对输入动态校验

简单案例 <el-form :model"Form" :rules"rules" ref"FormRef" class"formDiv"><el-table :data"Form.copyWriters" style"width: 100%"><el-table-column label"文案链接"><temp…

Day33:安全开发-JavaEE应用SQL预编译Filter过滤器Listener监听器访问控制

目录 JavaEE-预编译-SQL JavaEE-过滤器-Filter JavaEE-监听器-Listen 思维导图 Java知识点 功能&#xff1a;数据库操作&#xff0c;文件操作&#xff0c;序列化数据&#xff0c;身份验证&#xff0c;框架开发&#xff0c;第三方库使用等. 框架库&#xff1a;MyBatis&#…

Mysql锁与MVCC

文章目录 Mysql锁的类型锁使用MVCC快照读和当前读读视图【Read View】串行化的解决 exlpain字段解析ACID的原理日志引擎整合SpringBoot博客记录 Mysql锁的类型 MySQL中有哪些锁&#xff1a; 乐观锁&#xff08;Optimistic Locking&#xff09;&#xff1a;假设并发操作时不会发…

C语言程序环境和预处理Pt.1 - 预处理指令|预处理操作符

电脑所能识别的语言为二进制指令&#xff0c;而我们所写的C语言代码是文本信息。为了能使计算机识别并执行C语言代码&#xff0c;就需要翻译环境&#xff0c;使C语言代码翻译为二进制的指令。 1.按下编译按钮的幕后 - 程序的翻译环境 从C语言源代码到计算机可识别的二进制文件…

MTK安卓开发板_联发科开发板评估套件_安卓主板硬件开发

在介绍开发板之前&#xff0c;让我们先来区分一下核心板和开发板的区别。核心板是一种集成度高、功能完整的计算模块&#xff0c;搭载系统&#xff0c;简化了外围接口&#xff0c;体积尺寸相对较小&#xff0c;主要适用于嵌入式系统。而开发板由核心板底板组成&#xff0c;提供…

spring中事务失效的场景有哪些?

异常捕获处理 在方法中已经将异常捕获处理掉并没有抛出。 事务只有捕捉到了抛出的异常才可以进行处理&#xff0c;如果有异常业务中直接捕获处理掉没有抛出&#xff0c;事务是无法感知到的。 解决&#xff1a;在catch块throw抛出异常。 抛出检查异常 spring默认只会回滚非检…

EI级 | Matlab实现PCA-GCN主成分降维结合图卷积神经网络的数据多特征分类预测

EI级 | Matlab实现PCA-GCN主成分降维结合图卷积神经网络的数据多特征分类预测 目录 EI级 | Matlab实现PCA-GCN主成分降维结合图卷积神经网络的数据多特征分类预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现PCA-GCN主成分降维结合图卷积神经网络的数据多…

c/c++ | 求叶子结点个数 |构建B树 | 动态规划--找叶子结点个数

是这样的&#xff0c;一道代码题&#xff0c;根据输入数据&#xff0c;计算运行结果 #include<bits/stdc.h> using namespace std; vector<int>g[10]; int ans 0; void dfs(int x){if(g[x].size() 0){ans;return;}for(int i 0; i < g[x].size(); i){dfs(g[x]…

windows 安装 gitlab-runner CICD

点击搜索图标 手动输入PowerShell, 右键点击管理员权限打开&#xff0c; 一、安装 安装 gitlab runner 文档参考地址 1、下载exe执行文件 我这里是 win64 https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-windows-amd64.exe 2、创建 gitla…

基于java+springboot+vue实现的电影订票系统(文末源码+Lw+ppt)23-41

摘 要 随着网络科技的不断发展以及人们经济水平的逐步提高&#xff0c;计算机如今已成为人们生活中不可缺少的一部分&#xff0c;为电影订票方便管理&#xff0c;基于java技术设计与实现了一款简洁、轻便的管理系统。本系统解决了电影订票事务中的主要问题&#xff0c;包括个…

08.JavaScript中的编程思想,构造函数和原型对象

一、编程思想 学习 JavaScript 中基于原型的面向对象编程序的语法实现&#xff0c;理解面向对象编程的特征。 1.面向过程 面向过程就是分析出解决问题所需要的步骤&#xff0c;然后用函数把这些步骤一步一步实现&#xff0c;使用的时候再一个一个的依次 调用就可以了。 举个…

JAVA初阶数据结构栈(工程文件后续会上传)(+专栏数据结构练习是完整版)

1.栈的概念讲解(Stack)&#xff09; 定义&#xff1a;栈是一种先进后出的数据结构 要想拿到12就要把它头上的所有东西给移出去 2.栈的实现&#xff08;代码&#xff09; 2.1栈的方法逻辑的讲解 &#xff08;1&#xff09;新建一个测试类Frank &#xff08;2&#xff09;进…

基于STM32的智慧农业管理系统设计与实现

文章目录 一、前言1.1 项目介绍【1】项目功能【2】设计实现的功能【3】项目硬件模块组成 1.2 设计思路1.3 传感器功能介绍1.4 开发工具的选择 二、EMQX开源MQTT服务器框架三、购买ECS云服务器3.1 登录官网3.2 购买ECS服务器3.3 配置安全组3.4 安装FinalShell3.5 远程登录到云服…

后端给前端导出 数据excal表

pom <!-- 读取文档 --><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.15</version></dependency><!-- https://mvnrepository.com/artifact/org.apache.poi/poi --><…

最新CLion + STM32 + CubeMX 开发环境搭建

网上有不少相关教程&#xff0c;但都是基于老版本Clion&#xff0c;新版有一些改变&#xff0c;但整体是简单了。 PS&#xff1a;本教程基于CLion 2023.3.4 安装所需工具参考&#xff1a;Clion搭建stm32开发环境&#xff08;STM32F103C8T6&#xff09;&#xff0c;有这一篇就够…

BFS(宽度优先搜索)C++(Acwing)

代码&#xff1a; #include <cstring> #include <iostream> #include <algorithm>using namespace std;typedef pair<int, int> PII;const int N 110;int n, m; int g[N][N]; int d[N][N]; PII q[N * N];int bfs() {int hh 0, tt 0;q[0] {0, 0};m…

C#,图论与图算法,输出无向图(Un-directed Graph)全部环(cycle)的算法与源代码

1 无向图(Un-directed Graph)全部环 图算法中需要求解全部的环。 2 方法 使用图着色方法,用唯一的数字标记不同循环的所有顶点。图形遍历完成后,将所有类似的标记数字推送到邻接列表,并相应地打印邻接列表。 3 算法 将边插入到邻接列表中。调用DFS函数,该函数使用着色方…