Spring Cloud 实战系列之 Zuul 微服务网关搭建及配置

一、创建SpringBoot项目

在这里插入图片描述
在这里插入图片描述
用mavan搭建也可以。(重要的是后面pom里应该引入那些依赖,application.yml怎么配置)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

由于开始构建项目时选择了Eureka Server,所以pom.xml中不需要手动添加依赖了

首先在启动类SpringcloudApplication中添加EurekaServer的注解:@EnableEurekaServer
在这里插入图片描述
在这里插入图片描述

二、application.yml

server:port: 9000  #eureka注册中心服务端口eureka:instance:hostname: localhostclient:register-with-eureka: false #不向eureka注册中心注册。也就是为了关闭自己向自己注册,eureka默认要向自己注册fetch-registry: falseservice-url:defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

在这里插入图片描述
访问注册中心:按照配置的端口号访问。我这里配了9000,端口随意,如下图代表Eureka注册中心部署成功了。
显示没有实例在此中心注册。没事接下来我们开始配置zuul网关,它也是一个服务需要注册到此注册中心来。
在这里插入图片描述

三、提供Service服务

eurekaservice01,eurekaservice02,eurekaservice03,eurekaservice04,第一个如下,第二三四个按着第一个的建,修改一下名字,端口号还有方法返回值
在这里插入图片描述
需要用到mvc
在这里插入图片描述
服务提供者同样需要注册到注册中心
在这里插入图片描述
在这里插入图片描述

接下来是同样的套路,改yml,启动类添加注解:@EnableEurekaClient
yml配置如下(因为是测试所有很简陋):

server:port: 8900 # 服务提供方# 指定当前eureka客户端的注册地址,
eureka:client:service-url:defaultZone: http://${eureka.instance.hostname}:9000/eureka/instance:hostname: localhost#当前服务名称
spring:application:name: eurekaservice1

注意当前服务名称。这里用于注册到注册中心的名字,还可以启动很多同样为eurekaservice1的名字的微服务到注册中心,zuul从注册中心Eureka Server获取所有服务名为eurekaservice01的服务列表后,会采用负载均衡策略访问其中一台服务提供者获取资源。

下图我们之前zuul中的配置serviceId就是指向这里的服务名称,这是微服务调用的精髓,通过服务名调用。
既然是服务提供者 ,这里要编写controller类了:新建controller包,新建Test01类,编写REST的方法。返回服务1
在这里插入图片描述
按照服务提供者1的搭建方式,现在搭建服务提供者2:
同样是新建模组,名字改为…02,yml配置文件中端口号与服务1要不同,服务名称相同,为了测试负载均衡,REST方法返回值设为服务2。
在这里插入图片描述
在这里插入图片描述

server:port: 8901 # 服务提供方# 指定当前eureka客户端的注册地址,
eureka:client:service-url:defaultZone: http://${eureka.instance.hostname}:9000/eureka/instance:hostname: localhost#当前服务名称
spring:application:name: eurekaservice1

同样的方法再建两个服务提供者3和4,服务名称都为eurekaservice2,端口号分别为8902,和8903。REST方法返回值分别为,服务3和服务4。
在这里插入图片描述
在这里插入图片描述

四、Zuul网关服务

搭建了注册中心,和服务的提供者,我们现在开始搭建Zuul网关服务,最后通过zuul访问注册中心获取服务列表,然后访问服务提供者。
在这里插入图片描述
这里模组名设为zuul。包名设置为zuul,等会生成的启动类就会是带有zuul了。EurekaServer也可以这样只是我开始搭的时候没有注意到。
在这里插入图片描述
要Eureka的客户端组件,和zuul组件,点next
在这里插入图片描述
在这里插入图片描述
模组名设为zuul,不强制
在这里插入图片描述
项目结构:
在这里插入图片描述
在启动类配置注解 @EnableEurekaClient,@EnableZuulProxy,@EnableZuulProxy可以称为@EnableZuulServer的增强版,当Zuul与Eureka、Ribbon等组件配合使用时,我们使用@EnableZuulProxy
在这里插入图片描述
配置pom文件:

在这里插入图片描述
启动项目
在这里插入图片描述
再去注册中心看就能看见zuul服务已经被注册到注册中心了
在这里插入图片描述

五、Zuul的访问

有一个网关服务zuul,一个注册中心eurekaserver,4个服务提供者eurekaservice,4个服务提供者

其中两个提供服务名为eurekaservice1的服务,另外两个提供eurekaservice2的服务,现在我们来启动4个服务提供者,在注册中心查看,并通过网关访问测试网关的服务是否正常。

总项目结构:
在这里插入图片描述
启动后注册中心查看:
在这里插入图片描述

如之前所想,两个服务名下各两台服务提供者。
现在回想之前zuul的路由配置:
在这里插入图片描述
访问zuul网关的test01/**下的任何服务都会给我转发到服务名为eurekaservice1下的01和02服务下。

第一次访问:test01
在这里插入图片描述
第二次访问:test01
在这里插入图片描述
可以看见zuul网关做了转发和负载均衡,使用的是ribbon轮询的方式负载均衡。
那么可以猜想到我们访问test02,zuul网关会在服务名为eurekaservice2的服务3和服务4之间去访问了。我们来看看:
在这里插入图片描述
在这里插入图片描述
至此已经实践完成zuul网关的基本功能转发和负载均衡。

Zuul网关的应用

通过zuul访问服务的,URL地址默认格式为:http://zuulHostIp:port/要访问的服务名称/服务中的URL

服务名称:properties配置文件中的spring.application.name
服务的URL:就是对应的服务对外提供的URL路径监听

一、网关依赖注入

<!-- spring cloud Eureka Client 启动器 -->
<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>
<!-- zuul网关的重试机制,不是使用ribbon内置的重试机制是借助spring-retry组件实现的重试开启zuul网关重试机制需要增加下述依赖-->
<dependency><groupId>org.springframework.retry</groupId><artifactId>spring-retry</artifactId>
</dependency>

二、启动类

/*** @EnableZuulProxy - 开启Zuul网关。*  当前应用是一个Zuul微服务网关。会在Eureka注册中心中注册当前服务。并发现其他的服务。*  Zuul需要的必要依赖是spring-cloud-starter-zuul。*/
@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication {public static void main(String[] args) {SpringApplication.run(ZuulApplication.class, args);}
}

三、配置文件:网关全局变量配置

# URL路径匹配
# 使用路径方式匹配路由规则。
# 参数key结构:zuul.routes.customName.path=xxx
# 用于配置路径匹配规则。
# 其中customName自定义。通常使用要调用的服务名称,方便后期管理
# 可使用的通配符有:* ** ?
# ? 单个字符
# * 任意多个字符,不包含多级路径
# ** 任意多个字符,包含多级路径
zuul.routes.eureka-application-service.path=/api/**
# 参数key结构:zuul.routes.customName.url=xxx
# url用于配置符合path的请求路径路由到的服务地址。
zuul.routes.eureka-application-service.url=http://127.0.0.1:8080/# 服务名称匹配
# service id pattern 通过服务名称路由
# key结构 :zuul.routes.customName.path=xxx
# 路径匹配规则  符合path的请求路径直接路由到customName对应的服务上
zuul.routes.eureka-application-service.path=/api/**
# key结构 :zuul.routes.customName.serviceId=xxx
# serviceId用于配置符合path的请求路径路由到的服务名称。如果只配置path,不配置serviceId。则customName相当于服务名称
zuul.routes.eureka-application-service.serviceId=eureka-application-service# 路由排除配置
# 配置不被zuul管理的服务列表。多个服务名称使用逗号','分隔。
# 配置的服务将不被zuul代理。
zuul.ignored-services=eureka-application-service# 此方式相当于给所有新发现的服务默认排除zuul网关访问方式,只有配置了路由网关的服务才可以通过zuul网关访问
# 通配方式配置排除列表。
zuul.ignored-services=*
# 使用服务名称匹配规则配置路由列表,相当于只对已配置的服务提供网关代理。
zuul.routes.eureka-application-service.path=/api/**# 通配方式配置排除网关代理路径。所有符合ignored-patterns的请求路径都不被zuul网关代理。
zuul.ignored-patterns=/**/test/**
zuul.routes.eureka-application-service.path=/api/**# 路由前缀配置
# prefix URL pattern 前缀路由匹配
# 配置请求路径前缀,所有基于此前缀的请求都由zuul网关提供代理。
zuul.prefix=/api
# 使用服务名称匹配方式配置请求路径规则。
# 这里的配置将为:http://ip:port/api/appservice/**的请求提供zuul网关代理,可以将要访问服务进行前缀分类。
# 并将请求路由到服务eureka-application-service中。
zuul.routes.eureka-application-service.path=/appservice/**

网关配置方式有多种,默认、URL、服务名称、排除|忽略、前缀。
网关配置没有优劣好坏,应该在不同的情况下选择合适的配置方案。

zuul网关其底层使用ribbon来实现请求的路由,并内置Hystrix,可选择性提供网关fallback逻辑。使用zuul的时候,并不推荐使用Feign作为application client端的开发实现。毕竟Feign技术是对ribbon的再封装,使用Feign本身会提高通讯消耗,降低通讯效率,只在服务相互调用的时候使用Feign来简化代码开发就够了。而且商业开发中,使用Ribbon+RestTemplate来开发的比例更高。

四、路由网关过滤器

Zuul中提供了过滤器定义,可以用来过滤代理请求,提供额外功能逻辑。如:权限验证,日志记录等。

Zuul提供的过滤器是一个父类。父类是ZuulFilter。通过父类中定义的抽象方法filterType,来决定当前的Filter种类是什么。有前置过滤、路由后过滤、后置过滤、异常过滤。

  • 前置过滤:是请求进入Zuul之后,立刻执行的过滤逻辑
  • 路由后过滤:是请求进入Zuul之后,并Zuul实现了请求路由后执行的过滤逻辑,路由后过滤,是在远程服务调用之前过滤的逻辑。
  • 后置过滤:远程服务调用结束后执行的过滤逻辑。
  • 异常过滤:是任意一个过滤器发生异常或远程服务调用无结果反馈的时候执行的过滤逻辑。无结果反馈,就是远程服务调用超时。

过滤器实现方式

继承父类ZuulFilter。在父类中提供了4个抽象方法,分别是:filterType, filterOrder, shouldFilter, run。其功能分别是:

  • filterType:方法返回字符串数据,代表当前过滤器的类型。可选值有-pre, route, post, error。pre - 前置过滤器,在请求被路由前执行,通常用于处理身份认证,日志记录等;
  • route - 在路由执行后,服务调用前被调用;
  • error - 任意一个filter发生异常的时候执行或远程服务调用没有反馈的时候执行(超时),通常用于处理异常;
  • post - 在route或error执行后被调用,一般用于收集服务信息,统计服务性能指标等,也可以对response结果做特殊处理。
  • filterOrder:返回int数据,用于为同filterType的多个过滤器定制执行顺序,返回值越小,执行顺序越优先
  • shouldFilter:返回boolean数据,代表当前filter是否生效
  • run:具体的过滤执行逻辑。如pre类型的过滤器,可以通过对请求的验证来决定是否将请求路由到服务上;如post类型的过滤器,可以对服务响应结果做加工处理(如为每个响应增加footer数据)。

过滤器的生命周期
在这里插入图片描述

/*** Zuul过滤器,必须继承ZuulFilter父类。* 当前类型的对象必须交由Spring容器管理。使用@Component注解描述。* 继承父类后,必须实现父类中定义的4个抽象方法。* shouldFilter、 run、 filterType、 filterOrder*/
@Component
public class LoggerFilter extends ZuulFilter {private static final Logger logger = LoggerFactory.getLogger(LoggerFilter.class);/*** 返回boolean类型。代表当前filter是否生效。* 默认值为false。* 返回true代表开启filter。*/@Overridepublic boolean shouldFilter() {return true;}/*** run方法就是过滤器的具体逻辑。* return 可以返回任意的对象,当前实现忽略。(spring-cloud-zuul官方解释)* 直接返回null即可。*/@Overridepublic Object run() throws ZuulException {// 通过zuul,获取请求上下文RequestContext rc = RequestContext.getCurrentContext();HttpServletRequest request = rc.getRequest();logger.info("LogFilter1.....method={},url={}",request.getMethod(),request.getRequestURL().toString());// 可以记录日志、鉴权,给维护人员记录提供定位协助、统计性能return null;}/*** 过滤器的类型。可选值有:* pre - 前置过滤* route - 路由后过滤* error - 异常过滤* post - 远程服务调用后过滤*/@Overridepublic String filterType() {return "pre";}/*** 同种类的过滤器的执行顺序。* 按照返回值的自然升序执行。*/@Overridepublic int filterOrder() {return 0;}
}

五、Zuul网关的容错(与Hystrix的无缝结合)

在spring cloud中,Zuul启动器中包含了Hystrix相关依赖,在Zuul网关工程中,默认是提供了Hystrix Dashboard服务监控数据的(hystrix.stream),但是不会提供监控面板的界面展示。可以说,在spring cloud中,zuul和Hystrix是无缝结合的。

1、Zuul中的服务降级处理

在Edgware版本之前,Zuul提供了接口ZuulFallbackProvider用于实现fallback处理。从Edgware版本开始,Zuul提供了ZuulFallbackProvider的子接口FallbackProvider来提供fallback处理。

Zuul的fallback容错处理逻辑,只针对timeout异常处理,当请求被Zuul路由后,只要服务有返回(包括异常),都不会触发Zuul的fallback容错逻辑。

因为对于Zuul网关来说,做请求路由分发的时候,结果由远程服务运算的。那么远程服务反馈了异常信息,Zuul网关不会处理异常,因为无法确定这个错误是否是应用真实想要反馈给客户端的。

2、代码示例

/*** 如果需要在Zuul网关服务中增加容错处理fallback,需要实现接口ZuulFallbackProvider* spring-cloud框架,在Edgware版本(包括)之后,声明接口ZuulFallbackProvider过期失效,* 提供了新的ZuulFallbackProvider的子接口 - FallbackProvider* 在老版本中提供的ZuulFallbackProvider中,定义了两个方法。*  - String getRoute()*    当前的fallback容错处理逻辑处理的是哪一个服务。可以使用通配符‘*’代表为全部的服务提供容错处理。*    如果只为某一个服务提供容错,返回对应服务的spring.application.name值。*  - ClientHttpResponse fallbackResponse()*    当服务发生错误的时候,如何容错。* 新版本中提供的FallbackProvider提供了新的方法。*  - ClientHttpResponse fallbackResponse(Throwable cause)*    如果使用新版本中定义的接口来做容错处理,容错处理逻辑,只运行子接口中定义的新方法。也就是有参方法。*    是为远程服务发生异常的时候,通过异常的类型来运行不同的容错逻辑。*/
@Component
public class TestFallBbackProvider implements FallbackProvider {/*** return - 返回fallback处理哪一个服务。返回的是服务的名称* 推荐 - 为指定的服务定义特性化的fallback逻辑。* 推荐 - 提供一个处理所有服务的fallback逻辑。* 好处 - 服务某个服务发生超时,那么指定的fallback逻辑执行。如果有新服务上线,未提供fallback逻辑,有一个通用的。*/@Overridepublic String getRoute() {return "eureka-application-service";}/*** fallback逻辑。在早期版本中使用。* Edgware版本之后,ZuulFallbackProvider接口过期,提供了新的子接口FallbackProvider* 子接口中提供了方法ClientHttpResponse fallbackResponse(Throwable cause)。* 优先调用子接口新定义的fallback处理逻辑。*/@Overridepublic ClientHttpResponse fallbackResponse() {System.out.println("ClientHttpResponse fallbackResponse()");List<Map<String, Object>> result = new ArrayList<>();Map<String, Object> data = new HashMap<>();data.put("message", "服务正忙,请稍后重试");result.add(data);ObjectMapper mapper = new ObjectMapper();String msg = "";try {msg = mapper.writeValueAsString(result);} catch (JsonProcessingException e) {msg = "";}return this.executeFallback(HttpStatus.OK, msg, "application", "json", "utf-8");}/*** fallback逻辑。优先调用。可以根据异常类型动态决定处理方式。*/@Overridepublic ClientHttpResponse fallbackResponse(Throwable cause) {System.out.println("ClientHttpResponse fallbackResponse(Throwable cause)");if(cause instanceof NullPointerException){List<Map<String, Object>> result = new ArrayList<>();Map<String, Object> data = new HashMap<>();data.put("message", "网关超时,请稍后重试");result.add(data);ObjectMapper mapper = new ObjectMapper();String msg = "";try {msg = mapper.writeValueAsString(result);} catch (JsonProcessingException e) {msg = "";}return this.executeFallback(HttpStatus.GATEWAY_TIMEOUT, msg, "application", "json", "utf-8");}else{return this.fallbackResponse();}}/*** 具体处理过程。* @param status 容错处理后的返回状态,如200正常GET请求结果,201正常POST请求结果,404资源找不到错误等。*  使用spring提供的枚举类型对象实现。HttpStatus* @param contentMsg 自定义的响应内容。就是反馈给客户端的数据。* @param mediaType 响应类型,是响应的主类型, 如:application、text、media。* @param subMediaType 响应类型,是响应的子类型, 如:json、stream、html、plain、jpeg、png等。* @param charsetName 响应结果的字符集。这里只传递字符集名称,如:utf-8、gbk、big5等。* @return ClientHttpResponse 就是响应的具体内容。*  相当于一个HttpServletResponse。*/private final ClientHttpResponse executeFallback(final HttpStatus status, String contentMsg, String mediaType, String subMediaType, String charsetName) {return new ClientHttpResponse() {/*** 设置响应的头信息*/@Overridepublic HttpHeaders getHeaders() {HttpHeaders header = new HttpHeaders();MediaType mt = new MediaType(mediaType, subMediaType, Charset.forName(charsetName));header.setContentType(mt);return header;}/*** 设置响应体* zuul会将本方法返回的输入流数据读取,并通过HttpServletResponse的输出流输出到客户端。*/@Overridepublic InputStream getBody() throws IOException {String content = contentMsg;return new ByteArrayInputStream(content.getBytes());}/*** ClientHttpResponse的fallback的状态码 返回String*/@Overridepublic String getStatusText() throws IOException {return this.getStatusCode().getReasonPhrase();}/*** ClientHttpResponse的fallback的状态码 返回HttpStatus*/@Overridepublic HttpStatus getStatusCode() throws IOException {return status;}/*** ClientHttpResponse的fallback的状态码 返回int*/@Overridepublic int getRawStatusCode() throws IOException {return this.getStatusCode().value();}/*** 回收资源方法* 用于回收当前fallback逻辑开启的资源对象的。* 不要关闭getBody方法返回的那个输入流对象。*/@Overridepublic void close() {}};}
}

六、Zuul网关的限流保护

Zuul网关组件也提供了限流保护。当请求并发达到阀值,自动触发限流保护,返回错误结果。只要提供error错误处理机制即可。

Zuul的限流保护需要额外依赖spring-cloud-zuul-ratelimit组件。

<dependency><groupId>com.marcosbarbero.cloud</groupId><artifactId>spring-cloud-zuul-ratelimit</artifactId><version>1.3.4.RELEASE</version>
</dependency>

1、全局限流配置

使用全局限流配置,zuul会对代理的所有服务提供限流保护。

# 开启限流保护
zuul.ratelimit.enabled=true
# 60s内请求超过3次,服务端就抛出异常,60s后可以恢复正常请求
zuul.ratelimit.default-policy.limit=3
zuul.ratelimit.default-policy.refresh-interval=60
# 针对IP进行限流,不影响其他IP
zuul.ratelimit.default-policy.type=origin

2、局部限流配置
使用局部限流配置,zuul仅针对配置的服务提供限流保护。

# 开启限流保护
zuul.ratelimit.enabled=true
# hystrix-application-client服务60s内请求超过3次,服务抛出异常。
zuul.ratelimit.policies.hystrix-application-client.limit=3
zuul.ratelimit.policies.hystrix-application-client.refresh-interval=60
# 针对IP限流。
zuul.ratelimit.policies.hystrix-application-client.type=origin

3、限流参数简介
在这里插入图片描述

七、Zuul网关性能调优:网关的两层超时调优

使用Zuul的spring cloud微服务结构图:
在这里插入图片描述
从上图中可以看出。整体请求逻辑还是比较复杂的,在没有zuul网关的情况下,app client请求app service的时候,也有请求超时的可能。那么当增加了zuul网关的时候,请求超时的可能就更明显了。

当请求通过zuul网关路由到服务,并等待服务返回响应,这个过程中zuul也有超时控制。zuul的底层使用的是Hystrix+ribbon来实现请求路由。结构如下:
在这里插入图片描述
zuul中的Hystrix内部使用线程池隔离机制提供请求路由实现,其默认的超时时长为1000毫秒。ribbon底层默认超时时长为5000毫秒。如果Hystrix超时,直接返回超时异常。如果ribbon超时,同时Hystrix未超时,ribbon会自动进行服务集群轮询重试,直到Hystrix超时为止。如果Hystrix超时时长小于ribbon超时时长,ribbon不会进行服务集群轮询重试。

那么在zuul中可配置的超时时长就有两个位置:Hystrix和ribbon。具体配置如下:

# 开启zuul网关重试
zuul.retryable=true
# hystrix超时时间设置
# 线程池隔离,默认超时时间1000ms
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=8000# ribbon超时时间设置:建议设置比Hystrix小
# 请求连接的超时时间: 默认5000ms
ribbon.ConnectTimeout=5000
# 请求处理的超时时间: 默认5000ms
ribbon.ReadTimeout=5000
# 重试次数:MaxAutoRetries表示访问服务集群下原节点(同路径访问);MaxAutoRetriesNextServer表示访问服务集群下其余节点(换台服务器)
ribbon.MaxAutoRetries=1
ribbon.MaxAutoRetriesNextServer=1
# 开启重试
ribbon.OkToRetryOnAllOperations=true

Spring-cloud中的zuul网关重试机制是使用spring-retry实现的。工程必须依赖下述资源:

<dependency><groupId>org.springframework.retry</groupId><artifactId>spring-retry</artifactId>
</dependency>

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot项目连接Redis报错:Connection refused: no further information

今天在使用SpringBoot连接Redis时发生了报错 明明Jedis能够连接成功为什么StringRedisTemplate就不行? 然后在网上找了一下说是关闭防火墙或者修改配置文件但是都不管用 最后发现是Redis在SpringBoot3之后yml的配置方式发生了改变 相较于之前多了一个前缀, 由于我刚开始没有…

项目风险管理的前提是对风险的认知

大家好&#xff0c;我是不会魔法的兔子&#xff0c; 一枚北京执业律师&#xff0c;创建[项目管理者的法小院儿]&#xff0c;持续从法律的角度分享项目管理中的风险问题及预防&#xff0c;让项目管理者能够提早发现与解决项目执行过程中的风险&#xff0c;同时欢迎大家一起交流…

论文解读--Mutual Interference Mitigation in PMCW Automotive Radar

PMCW汽车雷达的相互干扰抑制 摘要 针对相位调制连续波(PMCW)毫米波(mmWave)汽车雷达系统中存在的相互干扰问题进行了研究。对先进驾驶辅助系统(ADAS)的需求日益增长&#xff0c;导致配备在同一频段工作的毫米波雷达系统的车辆激增&#xff0c;导致相互干扰&#xff0c;可能会降…

WPF 滑动条样式

效果图&#xff1a; 浅色&#xff1a; 深色&#xff1a; 滑动条部分代码&#xff1a; <Style x:Key"RepeatButtonTransparent" TargetType"{x:Type RepeatButton}"><Setter Property"OverridesDefaultStyle" Value"true"/&g…

枚举类、泛型、API

枚举类 枚举类可以实现单例设计模式。 枚举的常见应用场景&#xff1a;用来表示一组信息&#xff0c;然后作为参数进行传输。 泛型 API

Qt 中Qwidget相关属性

文章目录 1. QWidget 核心属性1.1 enabled1.2 geometry1.2.1 window frame 的影响 1.3 windowTitle1.4 windowIcon1.4.1 qrc的使用 1.5 windowOpacity1.6 cursor1.7 focusPolicy1.8 styleSheet 1. QWidget 核心属性 在 Qt 中, 使⽤ QWidget 类表⽰ “控件”. 像按钮, 视图, 输…

今年Android面试必问的这些技术面,2024Android常见面试题

都说程序员是在吃青春饭&#xff0c;这一点的确有一点对的成分&#xff0c;以前我不这么认为&#xff0c;但随着年龄的增长&#xff0c;事实告诉我的确是这样的&#xff0c;过了30以后&#xff0c;就会发现身体各方面指标下降&#xff0c;体力和身心上都多少有点跟不上了&#…

Node.js中的缓存策略和缓存技巧

在Node.js中&#xff0c;缓存策略和缓存技巧是提升应用性能和用户体验的关键因素。通过有效地利用缓存&#xff0c;我们可以显著减少系统资源的消耗&#xff0c;加快数据访问速度&#xff0c;从而提升整体的网站性能。本文将针对Node.js中的缓存策略和缓存技巧展开深入探讨&…

Newtonsoft.Json

目录 引言 1、简单使用 1.1、官方案例 1.2、JsonConvert 2、特性 2.1、默认模式[JsonObject(MemberSerialization.OptIn/OptOut)] 2.2、序列化为集合JsonArrayAttribute/JsonDictionaryAttribute 2.3、序列化该元素JsonProperty 2.4、忽略元素JsonIgnoreAttribute 2.5、…

今天面试招了个18K的人,从腾讯出来的果然都有两把刷子···

公司前段时间缺人&#xff0c;也面了不少测试&#xff0c;前面一开始瞄准的就是中级的水准&#xff0c;也没指望来大牛&#xff0c;提供的薪资在15-20k&#xff0c;面试的人很多&#xff0c;但平均水平很让人失望。看简历很多都是4年工作经验&#xff0c;但面试中&#xff0c;不…

docker save 命令 docker load 命令 快速复制容器

docker save 命令 docker load 命令 1、docker save 命令2、docker load 命令 1、docker save 命令 docker save 命令用于在系统上把正在使用的某个容器镜像 导出成容器镜像文件保存下载&#xff0c;以便在其他系统上导入这个容器镜像文件 以便快速在其他服务器上启动相同的容…

找不到msvcp140.dll无法运行程序如何处理?分享5种解决方法

在计算机系统运行过程中&#xff0c;如果无法找到必要的动态链接库文件msvcp140.dll&#xff0c;可能会引发一系列的问题与故障。这个特定的dll文件是Microsoft Visual C Redistributable Package的一部分&#xff0c;对于许多基于此编译环境开发的应用程序至关重要。缺失msvcp…

C++的常用排序(未完待续)

注&#xff1a;本文以升序为例 一、冒泡排序 1.1 操作方法 步骤1比较相邻元素&#xff0c;如果前者比后者大&#xff0c;则交换它们。步骤2对头到尾&#xff0c;对所有元素按序执行一轮这样的操作(这样可以找到第一最大值)步骤3再从第一个元素开始&#xff0c;重复上述比较操…

智能驾驶规划控制理论学习02-基于搜索的路径规划方法

目录 一、路径搜索问题 二、图论基础 三、图搜索方法 1、广度优先搜索&#xff08;BFS&#xff09; bfs与dfs的区别 bfs的搜索过程 bfs的算法实现 2、迪杰斯特拉算法&#xff08;Dijkstra&#xff09; 核心思想 优先级队列 Dijkstra搜索过程 Dijkstra优缺点…

【.NET Core】深入理解IO - FileSteam流

【.NET Core】深入理解IO - FileSteam流 文章目录 【.NET Core】深入理解IO - FileSteam流一、IO流概述二、文件流FileStream2.1 FileStream概述2.2 FileStream检测流位置更改2.3 FileStream构造函数2.4 FileStream常用属性2.5 FileStream.Read方法2.6 FileStream.Write方法2.7…

插混、油混、增程式、轻混、强混,啥区别

这里写自定义目录标题 随着我国新能源汽车的大力推进&#xff0c;电车可以说是世界未来的主流&#xff0c;只不过现在是处在一个过渡时代 这是个好时代&#xff0c;因为我们见证并体验着历史过渡的细节 这是个不好的时代&#xff0c;因为我们可能只是未来新新人类的试验品 帮他…

MyBatis 学习(三)之 MyBatis 全局配置文件

目录 1 MyBatis 全局配置文件 2 properties 元素 3 setting 设置 4 typeAlianses 别名处理器 5 typeHandler 类型处理器 6 objectFacotry 对象工厂&#xff08;了解&#xff09; 7 plugins 插件&#xff08;了解&#xff09; 8 environments 运行环境 9 databaseIdPro…

今日arXiv最热大模型论文:点击即可播放!港中文发布大模型写歌神器!

一首歌&#xff0c;包含作词作曲两个部分。擅长作词or作曲就已经很牛了。比如方文山是周杰伦的御用作词人&#xff0c;而周杰伦写过很多耳熟能详的曲子。而兼具作词作曲才华的全能创作人却是难得一见。 最近港中文发布了一款歌曲创作大模型SongComposer&#xff0c;作词作曲都…

自测-1 打印沙漏

文章预览&#xff1a; 题目算法代码 题目 算法 以前做过这个&#xff0c;那次是c语言写的&#xff0c;一点一点处理一层一层完成&#xff0c;这次我换了一种语言用了另一种思想使用递归去写&#xff0c;还是我们要先求出应该有多少层这个很容易&#xff0c;中间输出部分我们算…

常见查找算法Java实现

顺序&#xff08;线性&#xff09;查找二分查找/折半查找插值查找斐波那契查找 线性查找 判断数列是否包含要求&#xff0c;如果找到了&#xff0c;就提示找到了&#xff0c;并给出下标值 // 线性查找 public static ArrayList<Integer> seqSearch(int[] arr, int value…