springboot在feign和线程池中使用TraceId日志链路追踪(最终版)-2
文章目录
- 简述
- 问题
- feign调用时给head加入traceId
- FeignConfig配置
- FeignConfig 局部生效
- feign拦截器和配置合并为一个文件(最终版)
- feign异步调用拦截器配置[不常用]
- 使用TTL自定义线程池
- 为什么需要TransmittableThreadLocal?
- 总结
- 参考和拓展阅读
简述
书接前文:SpringBoot使用TraceId日志链路追踪-1
在上文中我们使用了springboot+MDC+Log4j2支持链路ID打印,但是如果我们使用feigin调用其他服务,线程池如何获取链路id呢;这里我们要用到阿里的TTL,在多线程面试中也会常用问到一个问题那就是线程传递问题。刚好这里就实践以下具体用法,并且这也是一个很好的案例。
问题
Spring 默认的日志框架 Logback 中提供的 LogbackMDCAdapter 内部使用的是ThreadLocal,只有本线程才有效,子线程和下游的服务 MDC 里的值会丢失。
主要的难点是解决值传递问题,主要包括以下几个部分:
异步情况下(线程池)如何传递 MDC 中的 TraceId 到子线程
API Gateway 网关中如何传递 MDC 中的 TraceId
微服务之间互相远程调用时如何传递 MDC 中的 TraceId
阿里的TTL组件解决了线程池场景下的上下文传递问题。通过装饰线程池,TTL在任务提交时自动拷贝父线程的上下文到子线程,并在任务结束后清理副本,确保多级线程池调用链路完整。
feign调用时给head加入traceId
1.需要拦截feign的requst请求,并加入自定义的报文头信息
2.需要把这个拦截器配置到feign的配置项中
在application.yml配置文件里面,可以添加feign相关的配置信息,常见的配置信息有如下这些:
loggerLevel:日志级别,四个取值:
- NONE 不打印日志;
- BASIC:只打印请求方法、URL、响应状态码、执行时间。
- HEADERS:打印请求头、响应头的日志信息。
- FULL:打印所有日志。
连接配置参数
- connectTimeout:连接超时时间,单位毫秒:ms。
- readTimeout:读取超时时间,单位毫秒:ms。
- retryer:重试策略。
- requestInterceptors:自定义的拦截器,可以多个,是一个List集合。
- defaultRequestHeaders:默认的请求头信息。
- defaultQueryParameters:默认的查询参数信息。
- followRedirects: 是否允许重定向。
这里我们开启HEADERS级别的日志,方便本地服务调用时打印报文头我们可以查看是否TraceId信息;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import gyqx.spd.common.constants.GlobalConstants;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.jboss.logging.MDC;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import java.util.Optional;/*** @version 1.0.0* @Date: 2025/3/15 8:49* @Description: 自定义feigin请求拦截器加入traceId,甚至我们可以把前端携带的token信息和用户id等报文头也放进来,方便转发给下一个被调用的服务*/
@Slf4j
public class CustomFeignInterceptor implements RequestInterceptor {@Overridepublic void apply(RequestTemplate template) {// TODO 在这里可以实现一些自定义的逻辑,例如:用户认证log.info("Feign执行拦截器....");Optional.ofNullable(RequestContextHolder.getRequestAttributes()).map(it -> ((ServletRequestAttributes) it).getRequest()).ifPresent(it -> {String traceId = it.getHeader(GlobalConstants.GLOBAL_X_TRACE_ID);if (StringUtil.isEmpty(traceId)) {traceId = MDC.get(GlobalConstants.GLOBAL_X_TRACE_ID) == null ? null : MDC.get(GlobalConstants.GLOBAL_X_TRACE_ID).toString();}if (StringUtil.isNotBlank(traceId)) {MDC.put(GlobalConstants.GLOBAL_X_TRACE_ID, traceId);template.header(GlobalConstants.GLOBAL_X_TRACE_ID, traceId);}log.info("Feign执行拦截器traceId={}", traceId);});}
}
FeignConfig配置
一般都是全局配置,每个服务引入依赖自动配置生效,当然如果只测试可以在某个feigin上自己加上
import feign.RequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @version 1.0.0* @Date: 2024/3/15 8:53* @Description: OpenFeign 配置类全局生效(直接放入核心配置,其他服务引入该依赖项即可)*/
@Configuration
public class FeignConfig {/*** 注入自定义的拦截器*/@Beanpublic RequestInterceptor requestInterceptor() {return new CustomFeignInterceptor();}}
FeignConfig 局部生效
以下方式皆可
- 把上面的配置文件FeignConfig只放入某个服务中生效(本文就是这种)
- yam中配置只对某个服务生效时配置
# feign 配置
feign:client:config:# 这里写微服务的服务名称,例如:我这里写的是 service-provider 服务名称# 针对 service-provider 微服务的请求,都将执行这些配置信息service-provider:loggerlevel: full# 配置请求拦截器,可以多个requestInterceptors:- com.gitee.code.interceptor.CustomFeignInterceptor
feign拦截器和配置合并为一个文件(最终版)
上面的写法是拦截器和配置文件分开了,当然我们可以缩写直接合并为一个文件,全局生效即可;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import gyqx.spd.common.constants.GlobalConstants;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.jboss.logging.MDC;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import java.util.Optional;/*** @version 1.0.0* @Date: 2024/3/15 8:53* @Description: OpenFeign 配置类+拦截器*/
@Slf4j
@Configuration
public class FeignConfig {/*** 注入自定义的拦截器*/@Beanpublic RequestInterceptor requestInterceptor() {return new RequestInterceptor(){@Overridepublic void apply(RequestTemplate template) {// TODO 在这里可以实现一些自定义的逻辑,例如:用户认证log.info("Feign执行拦截器....");Optional.ofNullable(RequestContextHolder.getRequestAttributes()).map(it -> ((ServletRequestAttributes) it).getRequest()).ifPresent(it -> {String traceId = it.getHeader(GlobalConstants.GLOBAL_X_TRACE_ID);if (StringUtil.isEmpty(traceId)) {traceId = MDC.get(GlobalConstants.GLOBAL_X_TRACE_ID) == null ? null : MDC.get(GlobalConstants.GLOBAL_X_TRACE_ID).toString();}log.info("Feign执行拦截器token:traceId={}", traceId);if (StringUtil.isNotBlank(traceId)) {MDC.put(GlobalConstants.GLOBAL_X_TRACE_ID, traceId);traceId= traceId.substring(traceId.indexOf(":") + 1);//我这里去掉了用户的token信息,不影响使用template.header(GlobalConstants.GLOBAL_X_TRACE_ID, traceId);}log.info("Feign执行拦截器traceId={}", traceId);});}};}@BeanLogger.Level feignLoggerLevel() {return Logger.Level.FULL;//日志级别全打印-方便调试,后续可以修改级别}
}
开启报文打印后,可以看到报文头里面已经有了traceId
在服务提供方的日志中也可以看到拦截到了
feign异步调用拦截器配置[不常用]
对于上面的配置对异步阻塞调用,异步非阻塞调用的情况就不再适用,需要单独把请求头获取后放入本地ThreadLocal变量中,也就是有个备份,然后放入异步线程的请求头里面。
详细请参考下面的blog,这种异步的异步项目中很少用到,但是放入本地ThreadLocal变量中的方式倒是很常用,比如我们把当前登录用户的session信息放入当前线程的上下文环境中,方便在业务中获取当前用户的ID,部门,权限等数据。
而这里把请求头的数据用拦截器拿到后放入本地ThreadLocal变量中只是为了方便调用其他feign异步接口时获取到当前线程携带过来的数据防止被覆盖和清空,为给另一个异步操作参数做准备工作。
https://blog.csdn.net/LatiaoCanCode/article/details/144358227
原理比较简单,上文中的TraceId我们也是在拦截器中获取并存入了MDC的ThreadLocal变量,这里其实也是自定义了一个ThreadLocal变量用户存放请求头信息,甚至可以拓展这个ThreadLocal变量为当前线程上下文环境变量CurrentThreadContex专门存放前端调用携带过来的上文数据作为缓存在当前线程中,方便后续操作使用。
对于线程部分的配置则无需参考,没有什么实际意义直接参考下面的自定义线程池使用TraceId
使用TTL自定义线程池
异步请求丢失上文的问题,这些问题追根究底都是ThreadLocal惹得祸。
由于ThreadLocal只能保存当前线程的信息,不能实现父子线程的继承。
说到这,很多人想到了InheritableThreadLocal,确实InheritableThreadLocal能够实现父子线程间传递本地变量,但是你的程序如果采用线程池,则存在着线程复用的情况,这时就不一定能够实现父子线程间传递了,因为在线程在线程池中的存在不是每次使用都会进行创建,InheritableThreadlocal是在线程初始化时intertableThreadLocals=true才会进行拷贝传递。
失败样例
@Test
public void test() throws Exception {//单一线程池ExecutorService executorService = Executors.newSingleThreadExecutor();//InheritableThreadLocal存储InheritableThreadLocal<String> username = new InheritableThreadLocal<>();for (int i = 0; i < 10; i++) {username.set("公众号:牧竹子—"+i);Thread.sleep(3000);CompletableFuture.runAsync(()-> System.out.println(username.get()),executorService);}
}//打印如下
-----------------------
公众号:牧竹子—0
公众号:牧竹子—0
公众号:牧竹子—0
公众号:牧竹子—0
所以若使用的子线程是已经被池化的线程,从线程池中取出线下进行使用,是没有经过初始化的过程,也就不会进行父子线程的本地变量拷贝。
由于在日常应用场景中,绝大多数都是会采用线程池的方式进行资源的有效管理。
为什么需要TransmittableThreadLocal?
在Spring框架中,默认情况下,线程池的任务执行是通过java.util.concurrent包中的ThreadPoolExecutor实现的。然而,如果你想要在使用Spring框架的同时,利用阿里巴巴的TransmittableThreadLocal(TTL)来传递线程局部变量(ThreadLocal)的值到异步任务中,你可以通过自定义线程池配置来实现这一点。
线程中JUC默认父子线程传递的InheritableThreadlocal是在线程初始化时intertableThreadLocals=true才会进行拷贝传递。但是在线程中已经是初始化之后的线程无法获取新的拷贝所以总是初始值。
TransmittableThreadLocal是阿里巴巴开源的库,主要用于解决在使用线程池时,线程局部变量(ThreadLocal)不能正确地传递到异步任务中的问题。这在微服务架构或者使用Spring Boot进行异步处理时尤其重要
样例
@Test
public void test() throws Exception {//单一线程池ExecutorService executorService = Executors.newSingleThreadExecutor();//需要使用TtlExecutors对线程池包装一下executorService=TtlExecutors.getTtlExecutorService(executorService);//TransmittableThreadLocal创建TransmittableThreadLocal<String> username = new TransmittableThreadLocal<>();for (int i = 0; i < 10; i++) {username.set("公众号:牧竹子—"+i);Thread.sleep(3000);CompletableFuture.runAsync(()-> System.out.println(username.get()),executorService);}
}//打印如下
-----------------------
公众号:牧竹子—0
公众号:牧竹子—1
公众号:牧竹子—2
可以看到已经能够实现了线程池中的父子线程的数据传递。
在每次调用任务的时,都会将当前的主线程的TTL数据copy到子线程里面,执行完成后,再清除掉。同时子线程里面的修改回到主线程时其实并没有生效。这样可以保证每次任务执行的时候都是互不干涉。
替换 Spring 默认线程池 使用 alibaba 的 TtlRunnable进行替换。
<dependency><groupId>com.alibaba</groupId><artifactId>transmittable-thread-local</artifactId><version>2.14.4</version></dependency>
自定义线程池
import com.alibaba.ttl.TtlRunnable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.ThreadPoolExecutor;@Configuration
public class TaskThreadPoolConfig {@Autowiredprivate TaskThreadPoolProperties config;@Bean(name = "taskExecutor")public ThreadPoolTaskExecutor threadPoolTaskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();//核心线程池大小executor.setCorePoolSize(config.getCorePoolSize());//最大线程数executor.setMaxPoolSize(config.getMaxPoolSize());//队列容量executor.setQueueCapacity(config.getQueueCapacity());//活跃时间executor.setKeepAliveSeconds(config.getKeepAliveSeconds());//线程名字前缀executor.setThreadNamePrefix("MyExecutor-");// setRejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务// CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());executor.setWaitForTasksToCompleteOnShutdown(true);executor.setAwaitTerminationSeconds(120); //等待任务执行时间,如果超过这个时间还没有销毁就 强制销executor.setTaskDecorator(getTraceContextDecorator());//使用TTL包装executor.initialize();return executor;}private TaskDecorator getTraceContextDecorator() {return runnable -> TtlRunnable.get(() -> {try {//把父级值放入当前线程的MDC本地ThreadLocal中,log4j打印时使用MDC.put("traceId", GlobTraceContext.getTraceId());runnable.run();} finally {MDC.clear();}});}}
因为MDC默认使用的ThreadLocal缓存当前线程的值,因此这里不能在用MDC默认的方式,得使用TTL改写为TransmittableThreadLocal类型放线程变量;
GlobTraceContext
import cn.hutool.core.util.IdUtil;
import com.alibaba.ttl.TransmittableThreadLocal;/*** 基于TransmittableThreadLocal实现线程池安全的TraceID传递** @author wnhyang* @date 2025/3/3**/
public class GlobTraceContext {private static final TransmittableThreadLocal<String> TRACE_ID = new TransmittableThreadLocal<>();/*** 设置TraceID,并同步到Log4j2的MDC*/public static void setTraceId(String traceId) {TRACE_ID.set(traceId);}public static String getTraceId() {return TRACE_ID.get();}public static void clear() {TRACE_ID.remove();}public static String generateTraceId() {return IdUtil.simpleUUID();}
}
AsyncService
import gyqx.spd.outside.conf.GlobTraceContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;/*** 异步调用service* @author summer*/
@Service
@Slf4j
public class AsyncService {/*** 使用 @Async 注解 实现异步调用* taskExecutor为自定义线程池,指定自定义线程池* @return* @throws InterruptedException*/@Async("taskExecutor")public void async(){log.info("async异步任务开始: " + Thread.currentThread().getName());try {log.info("子线程traceId:: " + GlobTraceContext.getTraceId());// 模拟耗时操作(实际工作中,此处写业务逻辑处理)Thread.sleep(30000);} catch (InterruptedException e) {e.printStackTrace();}log.info("async异步任务完成");}
}
AsyncService
@RequestMapping("test")
public class TestController {@Autowiredprivate AsyncService asyncService;@Resourceprivate ThreadPoolTaskExecutor taskExecutor;//使用我们自定义的线程池@GetMapping("/async")public AjaxResult<String> async() {String traceId = UUID.randomUUID().toString();System.out.println("父亲线程traceId:" +traceId);GlobTraceContext.setTraceId(traceId);//异步执行CompletableFuture.runAsync(() -> asyncService.async(), taskExecutor);// asyncService.async();log.info("async异步任务调用成功");return AjaxResult.ok("async异步任务调用成功");}}
打印结果如下
父亲线程traceId:db9a27e4-549a-4a41-ba7d-25297d875dca
controller.HrpStockController : async异步任务调用成功
controller.AsyncService : async异步任务开始: MyExecutor-1
controller.AsyncService : 子线程traceId:: db9a27e4-549a-4a41-ba7d-25297d875dca
controller.AsyncService : async异步任务完成
总结
要实现线程池支持的全局链路追踪需要上一章节和本章节feign拦截器中都要使用TransmittableThreadLocal作为替换ThreadLocal类型MDC作为存放链路ID,同样在父子线程中想存放其他值也需要使用TransmittableThreadLocal类型。
这里我们需要把上一章,和本章的LogInterceptor,FeignConfig中的MDC.put前加上GlobTraceContext.setTraceId即可,在线程池配置中我们在包装TTL的时候执行任务前把获取到的,getTraceId()放入当前线程的MDC变量中,这样log4j打印日志即可拿到当前线程的traceId值
参考和拓展阅读
SpringBoot使用TraceId日志链路追踪-1
https://blog.csdn.net/zjcjava/article/details/146237248
微服务中使用阿里开源的TTL,优雅的实现身份信息的线程间复用
https://developer.aliyun.com/article/12012001056715.html
阿里开源支持缓存线程池的ThreadLocal Transmittable ThreadLocal(TTL)
https://www.cnblogs.com/xiaopotian/p/11056715.html
配置spring/springboot默认的异步线程池
https://www.cnblogs.com/duanxz/p/6084494.html?ivk_sa=1024320u
ThreadLocal父子线程数据传递
https://blog.csdn.net/zjcjava/article/details/125601123
相关文章:
springboot在feign和线程池中使用TraceId日志链路追踪(最终版)-2
文章目录 简述问题feign调用时给head加入traceIdFeignConfig配置FeignConfig 局部生效feign拦截器和配置合并为一个文件(最终版)feign异步调用拦截器配置[不常用] 使用TTL自定义线程池为什么需要TransmittableThreadLocal? 总结参考和拓展阅读…...
datawhale组队学习-大语言模型-task5:主流模型架构及新型架构
目录 5.3 主流架构 5.3.1 编码器-解码器架构 5.3.2 因果解码器架构 5.3.3 前缀解码器架构 5.4 长上下文模型 5.4.1 扩展位置编码 5.4.2 调整上下文窗口 5.4.3 长文本数据 5.5 新型模型架构 5.5.1 参数化状态空间模型 5.5.2 状态空间模型变种 5.3 主流架构 在预训…...
《Matplotlib三维可视化工业实践——从分子模拟到流体力学》
目录 编辑 一、工业三维可视化挑战 1.1 典型工业场景需求 1.2 技术痛点分析 二、Matplotlib三维可视化基础 2.1 三维坐标体系构建 2.2 核心三维绘图API 三、分子模拟可视化实战 3.1 晶体结构渲染 3.2 分子轨迹动态演示 四、流体力学场数据优化渲染 4.1 矢量场高效…...
【neo4j数据导出并在其他电脑导入】
停止服务 neo4j stop 导出 neo4j-admin database dump neo4j --to-path"C:\Users\12901\Downloads\test folder" 导入 将 .dump 文件放在一个目录中 mkdir /root/dump-directory mv /root/neo4j.dump /root/dump-directory/ 使用包含 .dump 文件的目录路径作为 …...
多智能体融合(Multi-Agent Fusion)
多智能体融合(Multi-Agent Fusion)是指在多智能体系统(MAS, Multi-Agent System)中,多个智能体(Agent)通过协作、竞争或共享信息,实现全局最优的智能决策和任务执行。该方法广泛应用…...
状态模式(State Pattern)
状态模式(State Pattern) 如果任务的执行过程是有多个不同状态的(比如初始化、运行中、完成等),你可以使用状态模式。每个状态可以有不同的行为,使得任务的状态管理更加清晰和可维护。 示例: …...
Linux网站搭建(新手必看)
1.宝塔Linux面板的功能 宝塔面板是一款服务器管理软件,可以帮助用户建立网站,一键配置服务器环境,使得用户通过web界面就可以轻松的管理安装所用的服务器软件。 2. 宝塔Linux面板的安装 宝塔官网地址:宝塔面板 - 简单好用的Linu…...
JavaEE进阶---Mybatis(预编译SQL即时SQL动态SQL标签池化技术说明)
文章目录 1.经典面试题(#{}和${}的区别)1.1关于#1.2关于$1.3情况下需要使用$ 2.数据库连接池2.1池化技术图解 3.动态SQL3.1if标签的使用3.2where标签的使用3.3set标签的使用 1.经典面试题(#{}和${}的区别) 1.1关于# 预编译SQL&a…...
Object.defineProperty()Proxy详解(Vue23数据劫持实现)
底层原理👇🏿 总结一下,结构应该包括: 1. 方法的基本作用和参数。 2. 数据描述符和存取描述符的区别。 3. 属性定义的内部处理流程。 4. 在Vue中的应用实例。 5. 常见错误和正确实践。 每个部分都要结合搜索结果的信息&…...
网页的性能优化
面试中如何回答"前端性能优化"问题 在面试中回答性能优化问题时,建议采用结构化表达方式,展示你的系统化思维和实战经验。以下是一个推荐的回答框架: 1. 开场概述 “前端性能优化是一个系统工程,我通常会从加载性能、…...
Vue 3中的Teleport:超越组件边界的渲染
Vue 3引入了许多新特性,其中之一便是Teleport。它为开发者提供了一种强有力的方式来控制组件的渲染位置,使得我们可以将组件的内容“传送”到DOM树的任何地方,而不仅仅局限于其父级组件的边界内。这在创建模态框、通知系统或任何需要脱离当前…...
JVM垃圾回收笔记01-垃圾回收算法
文章目录 前言1. 如何判断对象可以回收1.1 引用计数法1.2 可达性分析算法查看根对象哪些对象可以作为 GC Root ?对象可以被回收,就代表一定会被回收吗? 1.3 引用类型1.强引用(StrongReference)2.软引用(SoftReference…...
3.26学习总结
今天主要学习了内部类,但总感觉有点混乱,和之前的抽象啊,接口,多态等概念联系在一起感觉更混乱了,所以打算先把最近学的理清一遍,敲一遍代码再往后学...
京东--数据开发实习生--保险业务部门--一面凉经
Base: 本人投递的是后台开发岗位,调剂到数据开发岗位,京东的数据开发也做后台开发方面的工作,还包括算法、策略、数据挖掘和数据平台搭建之类的职责。面试内容基本只会问简历上的,在此基础上再去考察岗位职责相关的内…...
【Hugging Face 开源库】Diffusers 库 —— 扩散模型
Diffusers 的三个主要组件1. DiffusionPipeline:端到端推理工具__call__ 函数callback_on_step_end 管道回调函数 2. 预训练模型架构和模块UNetVAE(Variational AutoEncoder)图像尺寸与 UNet 和 VAE 的关系EMA(Exponential Moving…...
TypeScript(TS) 的使用初识
我将详细讲解 TypeScript(TS) 的使用。TypeScript 是由微软开发的一种开源编程语言,它是 JavaScript 的超集,通过引入静态类型和面向对象编程特性,增强了 JavaScript 的开发体验和代码质量。TypeScript 最终会被编译成…...
QTcpSocket多线程连接慢问题
20250325记录 环境:Qt5.14.2 64位 msvc编译 在多线程环境下,使用QTcpSocket实现客户端,发现在少部分电脑上,连接时间过长,定时器检查套接字状态时,发现连接处于QAbstractSocket::ConnectingState状态。 …...
Vue的实例
Every Vue application starts with a single Vue component instance as the application root. Any other Vue component created in the same application needs to be nested inside this root component. 每个 Vue 应用都以一个 Vue 组件实例作为应用的根开始。在同一个应…...
[AI绘图] ComfyUI 中自定义节点插件安装方法
ComfyUI 是一个强大的 AI 图像生成工具,支持自定义节点插件扩展其功能。本文介绍 ComfyUI 中安装自定义节点插件的三种方法,包括 Git Clone 方式、插件管理器安装方式,以及手动解压 ZIP 文件的方法,并分析它们的优缺点。 1. Git Clone 方法 使用 git clone 是最稳定且推荐…...
数据库第二周作业
数据库约束、常见语句等 数据库约束 主键约束 #创建表,把id设为主键 mysql> create table test02(-> id int primary key, #----主键约束-> name varchar(50)-> ); Query OK, 0 rows affected (0.02 sec) #插入数据测试 mysql> insert into te…...
Appium Inspector使用教程
1.下载最新版本 https://github.com/appium/appium-inspector/releases 2.本地启动一个Appium服务 若Android SDK已安装Appium服务,则在任意terminal使用appium启动服务即可 3.Appium Inspector客户端配置连接到Appium服务 Configuring and Starting a Session…...
【QT继承QLabel实现绘制矩形、椭圆、直线、多边形功能,并且支持修改大小,移动位置,复制,粘贴,删除功能】
文章目录 介绍绘制一个矩形(椭圆)roi绘制一个多边形roi对矩形roi的缩放:对多边形rio的缩放(移动点的位置) 介绍 绘制矩形,椭圆,直线实际用的都是是同一个思路:鼠标第一次点击就确定…...
Elasticsearch未授权访问漏洞
1、编辑elasticsearch.yml配置文件,添加认证相关配置 vim elasticsearch.ymlxpack.security.enabled: true xpack.license.self_generated.type: basic xpack.security.transport.ssl.enabled: true2、重启ElasticSearch # 重启方式可能略微不同 systemctl restar…...
怎么处理 Vue 项目中的错误的?
一、错误类型 任何一个框架,对于错误的处理都是一种必备的能力 在Vue 中,则是定义了一套对应的错误处理规则给到使用者,且在源代码级别,对部分必要的过程做了一定的错误处理。 主要的错误来源包括: 后端接口错误代码中本身逻辑错误二、如何处理 后端接口错误 通过axi…...
Elasticsearch原生linux部署集群 和docker部署集群
Easticsearch 是一个分布式的搜索和分析引擎,广泛应用于日志分析、全文检索、实时数据分析等场景。为了满足高可用性和高性能的需求,Elasticsearch 通常以集群的方式部署。部署 Elasticsearch 集群时,可以选择两种主要方式:原生 L…...
缓存设计模式
缓存设计模式(Cache Design Pattern)是一种用于存储和管理频繁访问数据的技术,旨在提高系统性能、降低数据库或后端服务的负载,并减少数据访问延迟。以下是几种常见的缓存设计模式,并用 Python Redis 进行示例代码实现…...
详解TCP的四次握手和三次挥手,以及里面每个阶段的状态
TCP 三次握手(连接建立) TCP 连接建立通过三次握手完成,确保双方同步初始序列号并确认可达性。 阶段说明 第一次握手 客户端 → 服务器:发送 SYN(同步请求),携带初始序列号 seq x。客户端状态…...
Linux文件目录管理指令详解(上篇)
Linux文件目录管理指令详解(上篇) 在Linux操作系统中,文件目录管理是基础且重要的技能。通过一系列指令,用户可以高效地浏览、创建、修改和删除文件及目录。本文将详细介绍Linux中常用的文件目录管理类指令,包括pwd、…...
BCC-应用程序组件分析
libbpf-tools/gethostlatency 追踪glibc中的getaddrinfo、gethostbyname、gethostbyname2函数用时 # /usr/share/bcc/libbpf-tools/gethostlatency TIME PID COMM LATms HOST 14:58:32 8418 curl 313.635 www.taobao.com以# cur…...
无参数读文件和RCE
什么是无参数? 无参数(No-Argument)的概念,顾名思义,就是在PHP中调用函数时,不传递任何参数。我们需要利用仅靠函数本身的返回值或嵌套无参数函数的方式,达到读取文件或远程命令执行࿰…...
SpringMVC_day02
一、SSM 整合 核心步骤 依赖管理 包含 SpringMVC、Spring JDBC、MyBatis、Druid 数据源、Jackson 等依赖。注意点:确保版本兼容性(如 Spring 5.x 与 MyBatis 3.5.x)。 配置类 SpringConfig:扫描 Service 层、启用事务管理、导入…...
在Linux、Windows系统上安装开源InfluxDB——InfluxDB OSS v2并设置开机自启的保姆级图文教程
一、进入InfluxDB下载官网 InfluxData 文档https://docs.influxdata.com/Install InfluxDB OSS v2 | InfluxDB OSS v2 Documentation...
LinkedIn数据抓取零风险指南:亮数据住宅代理实现企业级合规采集
亮数据住宅代理实现企业级合规采集 一、前言二、尝试使用三、使用体验高效稳定易用性:合规与安全:技术支持: 四、适用场景五、推荐程度六、试用地址 一、前言 最近一位猎头小伙伴找到我,说目前很多公司的出海业务都在招人&#x…...
ROS2的发展历史、核心架构和应用场景
以下是对**ROS2(Robot Operating System 2)**的发展历史、核心架构和应用场景的详细解析,覆盖其技术演变、关键特性和生态系统: 一、ROS2的诞生背景:从ROS1到ROS2 1. ROS1的历史与局限 ROS1的起源: 2007年…...
PHP eval 长度限制绕过与 Webshell 获取
在 PHP 代码中,如果 eval($param); 存在且长度受限,并且过滤了 eval 和 assert,仍然可以通过多种方法绕过限制,获取 Webshell。 源码 <?php $param $_REQUEST[param]; if(strlen($param)<17 && stripos($param,…...
自然语言处理(14:处理时序数据的层的实现)
系列文章目录 第一章 1:同义词词典和基于计数方法语料库预处理 第一章 2:基于计数方法的分布式表示和假设,共现矩阵,向量相似度 第一章 3:基于计数方法的改进以及总结 第二章 1:word2vec 第二章 2:word2vec和CBOW模型的初步实现 第二章 3:CBOW模型…...
Pytest的Fixture使用
概述 Pytest中的Fixture可以使得测试代码高度复用,同时对资源进行安全的管理,以及在复杂的测试场景用进行灵活的组合。 概念 Fixture:可重用的函数,用@pytest.fixture来进行装饰,用于为测试提供数据、环境或者服务作用域:控制Fixture的生命周期,默认是function,可设置…...
【蓝桥杯】每日练习 Day13
前言 今天做了不少题,但是感觉都太水了,深思熟虑之下主播决定拿出两道相对不那么水的题来说一下(其实还是很水)。 两道问题,一道是日期问题(模拟),一道是区间合并问题。 日期差值 …...
Vue3 中使用 vuedraggable 实现拖拽排序功能,分组拖拽
Vue3 中使用 vuedraggable 实现拖拽排序功能,分组拖拽 安装draggable npm install vuedraggablenext --save基础用法示例 <template><div class"app-container"><draggable v-model"list" item-key"id":group"…...
husky的简介以及如果想要放飞自我的解决方案
husky 是一个 Git Hooks 管理工具,它的主要作用是 在 Git 提交(commit)、推送(push)等操作时执行自定义脚本,比如代码检查(Lint)、单元测试(Test)、格式化代码…...
Maven工具学习使用(四)——仓库
仓库分类 对于Mavne来说,仓库只分为两类:本地仓库和远程仓库。当Maven根据坐标查询寻找构件的时候,它首先会查看本地仓库,如果本地仓库存在此构件,则直接使用;如果本地仓库不存在此构件,或者需要查看是否有更新的构件版本,Maven就会去远程仓库查找,发现需要的构件之后…...
【BFS】《单源、多源 BFS:图搜索算法的双生力量》
文章目录 前言单源BFS例题一、迷宫中离入口最近的出口二、 最小基因变化三、单词接龙四、为高尔夫比赛砍树 多源BFS例题一、 01 矩阵二、飞地的数量三、地图中的最高点四、地图分析 结语 前言 什么是单源、多源BFS算法问题呢? BFS(Breadth - First Sear…...
批量取消 PDF 文档中的所有超链接
在 PDF 文档中我们可以插入各种各样的文本也可以给文本设置字体,颜色等多种样式,同时还可以给文字或者图片添加上超链接,当我们点击超链接之后,就会跳转到对应的网页。有时候这会对我们的阅读或者使用形成一定的干扰,今…...
13.2 kubelet containerRuntime接口定义和初始化
本节重点总结 : containerRuntime 需要实现3类接口 管理容器的接口管理镜像的接口Streaming API 用于客户端与容器进行交互 type KubeGenericRuntime interface {kubecontainer.Runtimekubecontainer.StreamingRuntimekubecontainer.CommandRunner }containerRun…...
使用 gone.WrapFunctionProvider 快速接入第三方服务
项目地址:https://github.com/gone-io/gone 本文中源代码: esexamples/es 文章目录 1. gone.WrapFunctionProvider 简介2. 配置注入实现3. 实战示例:Elasticsearch 集成4. 使用方式5. 最佳实践6. 总结 在如何给Gone框架编写Goner组件…...
git 标签学习笔记
目录 轻量级标签 带注释的标签(推荐) 给指定 commit 打标签 推送单个标签,需要单独推送,代码推送不会推送标签 推送所有标签 删除标签 轻量级标签 git tag v1.0.0 只是简单地给当前 commit 打上 v1.0.0 标签。 带注释的标…...
【论文阅读】基于思维链提示的大语言模型软件漏洞发现与修复方法研究
这篇文章来自于 Chain-of-Thought Prompting of Large Language Models for Discovering and Fixing Software Vulnerabilities 摘要 软件安全漏洞在现代系统中呈现泛在化趋势,其引发的社会影响日益显著。尽管已有多种防御技术被提出,基于深度学习&…...
企业在人工智能创新与安全之间走钢丝
2025 年全球 AI/ML 工具使用量将激增,企业将 AI 融入运营之中,员工也将 AI 嵌入日常工作流程中。报告显示,企业对 AI/ML 工具的使用同比增长 3,000% 以上,凸显了各行各业迅速采用 AI 技术,以提升生产力、效率和创新水平…...
CSS动画
目录 一、核心概念与语法 1. keyframes 关键帧 2. animation 属性 二、动画调速函数(animation-timing-function) 1. 预设值 2. 贝塞尔曲线 3. 步进函数(steps()) 三、动画控制与交互 1. 暂停与恢复 2. JavaScript 控制…...
计算机视觉(CV)技术的优势和挑战
计算机视觉(CV)技术是人工智能领域中的一个重要分支,它主要通过让机器学会“看”和“理解”图像或视频来模拟人类视觉系统。以下是计算机视觉技术的一些优势和挑战: 优势: 自动化:计算机视觉技术可以实现…...