当前位置: 首页 > news >正文

SpringBoot项目使用slf4j的MDC日志打点功能

SpringBoot项目使用slf4j的MDC日志打点功能

物料准备:

1.自定义1个线程MDC打点工具类

2.配置logback打印MDC打点的traceId

3.配置webMVC使用MDC打点

4.配置ThreadPoolTaskExecutor使用MDC打点

5.配置HttpClient使用MDC打点

6.测试MDC日志打点效果

线程mdc打点工具类代码

package cn.ath.knowwikibackend.mdc;import cn.hutool.core.lang.UUID;
import org.slf4j.MDC;import java.util.Map;
import java.util.concurrent.Callable;/*** 线程mdc打点工具类*/
public class ThreadMdcUtil {public static void setTRaceIdIfAbsent() {if (MDC.get("traceId") == null) {MDC.put("traceId", UUID.fastUUID().toString());}}public static <T> Callable<T> wrap(final Callable<T> callable, final Map<String, String> context) {return () -> {if (context == null) {MDC.clear();} else {MDC.setContextMap(context);}setTRaceIdIfAbsent();try {//最终通过 callable.call执行线程任务return callable.call();} finally {MDC.clear();}};}public static Runnable wrap(final Runnable runnable,final Map<String,String> context){return ()->{if (context==null){MDC.clear(); //mdc上下文为空 就清掉mdc}else {MDC.setContextMap(context);  // mdc上下文不为空,要设置上下文为 context}setTRaceIdIfAbsent(); //设置mdc 记录traceIdtry {//最终通过 runnable.run 执行线程任务runnable.run();}finally {MDC.clear();}};}
}

配置logback 输出的日志格式,要输出mdc里定义的traceId

logging:file:path: ${user.home}/.${spring.application.name}/log/logback:rollingpolicy:max-file-size: 15MBmax-history: 10pattern: # 注意这里配置的 [%X{traceId}] 即输出mdc打点的traceId值console: "%date  %level [%thread] [%X{traceId}] %logger{10} [%file : %line] %msg%n"file: "%date  %level [%thread] [%X{traceId}] %logger{10} [%file : %line] %msg%n"level:cn.ath.knowwikibackend.rest: info

配置webMVC使用MDC打点

定义MvcTraceInterceptor,来拦截http请求进行mdc打点

package cn.ath.knowwikibackend.mdc;import cn.hutool.core.lang.UUID;
import org.slf4j.MDC;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** mvc trace拦截器,作用是 实现trace打点*/
public class MvcTraceInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//在请求头里拿一个 traceId ,拿不到就创建1个 traceIdString traceId = request.getHeader("traceId");if (traceId==null){traceId = UUID.fastUUID().toString();}// traceId记录到mdc中MDC.put("traceId",traceId);return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {//1个http请求 后台处理完毕后 ,从mdc中移除 traceIdMDC.remove("traceId");}
}

使用自定义的MvcTraceInterceptor

package cn.ath.knowwikibackend.mdc;import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MvcMdcConfig implements WebMvcConfigurer {/*** 配置spring mvc启用 mvc trace拦截器,实现trace打点* @param registry InterceptorRegistry*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new MvcTraceInterceptor()).addPathPatterns("/**");}
}

配置ThreadPoolTaskExecutor使用MDC打点

package cn.ath.knowwikibackend.mdc;import org.slf4j.MDC;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.io.Serializable;
import java.util.concurrent.*;
/*** 异步线程池 的mdc 包装器,作用是 让 async 异步任务 实现trace打点*/
public class AsyncThreadPoolMdcWrapper extends ThreadPoolTaskExecutor implements Serializable {private static final long serialVersionUID = -1530245553055682935L;@Overridepublic void execute(Runnable task) {// Runnable 类型的线程运行时  进行 mdc 打点记录super.execute(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));}@Overridepublic <T> Future<T> submit(Callable<T> task) {// Callable 类型的线程运行时  进行 mdc 打点记录return super.submit(ThreadMdcUtil.wrap(task,MDC.getCopyOfContextMap()));}@Overridepublic Future<?> submit(Runnable task) {//  Runnable 类型且返回Future的 线程运行时  进行 mdc 打点记录return super.submit(ThreadMdcUtil.wrap(task,MDC.getCopyOfContextMap()));}
}

配置ApacheHttpClient使用MDC打点

package cn.ath.knowwikibackend.mdc;import lombok.extern.slf4j.Slf4j;
import org.apache.http.Header;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.protocol.HttpContext;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import java.io.IOException;/*** 自定义 HttpRequestInterceptor,* 这里可以对外发的http请求 追加请求头/请求参数之类的配置** 这里 在 Header 里追加上本应用的traceId ,便于全局排查请求日志*/
@Component
@Slf4j
public class HttpClientTracedInterceptor implements HttpRequestInterceptor {@Overridepublic void process(HttpRequest httpRequest, HttpContext httpContext) throws HttpException, IOException {//从mdc 中取出traceId 然后追加到 外发的http请求头里String traceId = MDC.get("traceId");if (traceId != null){httpRequest.addHeader("traceId",traceId);}//打印出所有的http请求头for (Header header : httpRequest.getAllHeaders()) {log.info("req header item---->{}",header);}}
}

测试MDC日志打点效果

修改之前的异步线程池使用AsyncThreadPoolMdcWrapper 替换掉默认的ThreadPoolTaskExecutor

@Configuration
public class AsyncConfig {@Bean("asyncCountTestTaskExecutor")public AsyncThreadPoolMdcWrapper asyncCountTaskTest(){AsyncThreadPoolMdcWrapper executor = new AsyncThreadPoolMdcWrapper();//核心线程数5:线程池创建时候初始化的线程数executor.setCorePoolSize(5);//最大线程数10:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程executor.setMaxPoolSize(10);//缓冲队列100:用来缓冲执行任务的队列executor.setQueueCapacity(100);//允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁executor.setKeepAliveSeconds(60);//线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池executor.setThreadNamePrefix("countTestTaskAsync-");//线程池满了后新任务由 任务发起者的线程执行RejectedExecutionHandler callerRunsPolicy = new ThreadPoolExecutor.CallerRunsPolicy();executor.setRejectedExecutionHandler(callerRunsPolicy);executor.initialize();return executor;}@Bean("asyncVoidTestTaskExecutor")public AsyncThreadPoolMdcWrapper asyncVoidTaskTest(){AsyncThreadPoolMdcWrapper executor = new AsyncThreadPoolMdcWrapper();//核心线程数5:线程池创建时候初始化的线程数executor.setCorePoolSize(5);//最大线程数10:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程executor.setMaxPoolSize(10);//缓冲队列100:用来缓冲执行任务的队列executor.setQueueCapacity(100);//允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁executor.setKeepAliveSeconds(60);//线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池executor.setThreadNamePrefix("voidTestTaskAsync-");//线程池满了后新任务由 任务发起者的线程执行RejectedExecutionHandler callerRunsPolicy = new ThreadPoolExecutor.CallerRunsPolicy();executor.setRejectedExecutionHandler(callerRunsPolicy);executor.initialize();return executor;}
}

在API接口中测试

@Slf4j
@RestController
@RequestMapping("/third")
public class TestApi {@AutowiredHttpClientTracedInterceptor httpClientTracedInterceptor;@Autowiredprivate AsyncAllService asyncAllService@GetMapping("/t1")public String te() throws ExecutionException, InterruptedException, IOException {log.trace("trace---test!!!!!");log.info("info---test!!!!!");log.warn("warn---test!!!!!");log.debug("debug---test!!!!!");log.error("error---test!!!!!");//有返回值的async任务Future<Long> longFuture = asyncAllService.testCount1();//无返回值的async任务asyncAllService.testAsync2();//有返回值的async任务,需要future执行后,最后统一get返回值Long l605 = longFuture.get();log.info("async task res:{}",l605);//测试使用apache httpclient 外发1个http请求String content = "test.dhrth.xxx.zzzdfg.derferf.sregvreg.regetg.esrtg34gf3";String url = "http://10.1.5.212:8008/api/getresult";Map<String, String> mapData = new HashMap<String, String>();mapData.put("type", "NER_RE");mapData.put("text", content);Map<String, Object> map = new HashMap<String, Object>();map.put("sid", "re");map.put("data", mapData);String reqStr = JSON.toJSONString(map);// 获取httpclientCloseableHttpClient httpclient = HttpClients.custom().addInterceptorFirst(httpClientTracedInterceptor).build();//创建post请求HttpPost httpPost = new HttpPost(url);RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(20*1000).setConnectionRequestTimeout(1000).setConnectTimeout(1000).build();httpPost.setConfig(requestConfig);StringEntity entity = new StringEntity(reqStr, ContentType.APPLICATION_JSON);httpPost.setEntity(entity);CloseableHttpResponse response = httpclient.execute(httpPost);// 得到响应信息int statusCode = response.getStatusLine().getStatusCode();log.info("http-res-statusCode:{}",statusCode);String respStr = EntityUtils.toString(response.getEntity(), "utf-8");log.info("http-resp:{}",respStr);return "thirdTestApi测试!";}
}    

测试控制台输出的日志效果

2023-06-05 15:45:54,228  INFO [http-nio-8080-exec-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.s.l.ReqLogAspect [ReqLogAspect.java : 94] 请求URI:/kwb/third/t1
2023-06-05 15:45:54,251  INFO [http-nio-8080-exec-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.s.l.ReqLogAspect [ReqLogAspect.java : 107] 请求目标类:String cn.ath.knowwikibackend.rest.TestApi.te()
2023-06-05 15:45:54,254  INFO [http-nio-8080-exec-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.r.TestApi [TestApi.java : 60] info---test!!!!!
2023-06-05 15:45:54,254  WARN [http-nio-8080-exec-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.r.TestApi [TestApi.java : 61] warn---test!!!!!
2023-06-05 15:45:54,255  ERROR [http-nio-8080-exec-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.r.TestApi [TestApi.java : 63] error---test!!!!!
2023-06-05 15:45:54,299  INFO [countTestTaskAsync-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.a.b.AsyncAllService [AsyncAllService.java : 35] now:2023-06-05 15:45:54
2023-06-05 15:45:54,299  INFO [voidTestTaskAsync-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.a.b.AsyncAllService [AsyncAllService.java : 52] now:2023-06-05 15:45:54
2023-06-05 15:45:54,300  INFO [countTestTaskAsync-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.a.b.AsyncAllService [AsyncAllService.java : 36] ---exec testCount1------------
2023-06-05 15:45:54,300  INFO [voidTestTaskAsync-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.a.b.AsyncAllService [AsyncAllService.java : 53] ---exec testAsync2------------
2023-06-05 15:45:54,300  INFO [http-nio-8080-exec-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.r.TestApi [TestApi.java : 73] async task res:8
2023-06-05 15:45:54,352  INFO [http-nio-8080-exec-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.m.HttpClientTracedInterceptor [HttpClientTracedInterceptor.java : 36] req header item---->traceId: 8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4
2023-06-05 15:45:55,429  INFO [http-nio-8080-exec-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.r.TestApi [TestApi.java : 109] http-res-statusCode:200
2023-06-05 15:45:55,431  INFO [http-nio-8080-exec-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.r.TestApi [TestApi.java : 121] http-resp:{"status": "OK","message": "提取成功","result": {}
}
2023-06-05 15:45:55,432  INFO [http-nio-8080-exec-1] [8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4] c.a.k.s.l.ReqLogAspect [ReqLogAspect.java : 125] Around请求耗时:1227ms
从日志中可以看到,1次浏览器请求进到app后,从切面就开始mdc打点,之后的异步线程操作 和 外发http操作 的log日志中都显示出了本次浏览器请求对应的后台日志的打点traceId值为 8e5e137d-1bb0-49bc-b7da-c8b9f6568ef4

相关文章:

SpringBoot项目使用slf4j的MDC日志打点功能

SpringBoot项目使用slf4j的MDC日志打点功能 物料准备&#xff1a; 1.自定义1个线程MDC打点工具类 2.配置logback打印MDC打点的traceId 3.配置webMVC使用MDC打点 4.配置ThreadPoolTaskExecutor使用MDC打点 5.配置HttpClient使用MDC打点 6.测试MDC日志打点效果 线程mdc打…...

宝塔修改默认端口后面板打不开

1、查看防火墙开启的端口&#xff0c;发现没有开启8888 [rootVM-12-12-centos ~]# firewall-cmd --list-ports 20/tcp 21/tcp 22/tcp 80/tcp 888/tcp 8081/tcp 39000-40000/tcp 8081/udp 2、防火墙开启8888端口 [rootVM-12-12-centos ~]# firewall-cmd --zonepublic --add-por…...

tinkerCAD案例:3.基本按钮

基本按钮 在本课中&#xff0c;您将学习制作具有圆柱形状的基本按钮。 说明 将圆柱体拖动到工作平面。 将其缩小到 2 毫米的高度。 提示&#xff1a; 您可以使用圆柱形状顶部的白点缩小圆柱体。 将其缩小到直径 16 毫米。 这将是按钮的主要形状。 现在我们可以创建允许将纽…...

客户线上反馈:从信息搜集到疑难 bug 排查全流程经验分享

写在前面&#xff1a;本文是我在前端团队的第三次分享&#xff0c;应该很少会有开发者写客户反馈处理流程以及 bug 排查的心得技巧&#xff0c;全文比较长&#xff0c;写了一个多星期大概1W多字&#xff08;也是我曾经2年工作的总结&#xff09;&#xff0c;如果你有耐心阅读&a…...

悲观锁、乐观锁、自旋锁

悲观锁、乐观锁、自旋锁 &#xff08;1&#xff09;乐观锁 乐观锁是一种乐观的思想&#xff0c;即认为读多写少&#xff0c;遇到并发的可能性低&#xff0c;每次拿数据时都认为别人不会修改&#xff0c;所以不会上锁&#xff0c;但是在更新的时候会判断一下在此期间别人有没有…...

七、进程地址空间

一、环境变量 &#xff08;一&#xff09;概念 环境变量(environment variables)&#xff1a;系统当中用做特殊用途的系统变量。 如&#xff1a;我们在编写C/C代码的时候&#xff0c;在链接的时候&#xff0c;从来不知道我们的所链接的动态静态库在哪里&#xff0c;但是照样可…...

浅谈智能微电网供电系统的谐波治理

摘要&#xff1a;智能微电网供电系统的特性容易引发谐波&#xff0c;而谐波导致电力损耗加大&#xff0c;降低供电质量。本文从谐波的产 生原因和危害做出详细阐述&#xff0c;并结合智能微电网提出了治 理谐波的方法和措施。 关键词&#xff1a;智能微电网&#xff1b;谐波危害…...

springboot项目的社区/博客系统

课前导读&#xff1a; 你学完一篇&#xff0c;你就多会一项技能&#xff0c;多多少少对你还是有点帮助的不是吗&#xff1f;~~~ 这是博主网页的url&#xff1a;优文共享社区 开发环境&#xff1a;JDK1.8&#xff0c;IDEA2021&#xff0c;MySQL5.7&#xff0c;Windows11 开发技术…...

go语言基础——函数、结构体、接口

由于go不是一门面向对象的语言&#xff0c;因此在有一些特性上和java是有一些区别的&#xff0c;比如go中就没有类这样的概念。下面来介绍一下go的一些特性。 结构体 结构体类似与java中的类&#xff0c;但又不完全一样。在类中&#xff0c;可以定义字段和方法&#xff0c;但…...

项目集管理—项目集治理

一、概述 项目集治理是实现和执行项目集决策&#xff0c;为支持项目集而制定实践&#xff0c;并维持项目集监督的绩效领域。 本章包括&#xff1a; 项目集治理实践项目集治理角色项目集治理设计与实施 项目集治理包括为了满足组织战略和运营目标的要求&#xff0c;对项目集实…...

MySQL了解之复制(一)

1.1、复制解决的问题 数据复制技术有以下一些特点&#xff1a; (1) 数据分布 (2) 负载平衡(load balancing) (3) 备份 (4) 高可用性(high availability)和容错 1.2、复制如何工作 从高层来看&#xff0c;复制分成三步&#xff1a; (1) master将改变记录到二进制…...

Halcon得出三角形内切圆

Halcon得出三角形内切圆 news2023/5/27 7:14: 目录 一、得出三角形的三个角点二、用类似尺规作图法得出三角形圆心 1、以三角形三角点画出圆形轮廓2、求出三角形轮廓与圆形轮廓之间的交点3、获得角平分线&#xff0c;三边角平分线交点为圆心三、求出圆心到边最短距离即半径 …...

2023年6月北京/广州/深圳CDGA/CDGP数据治理认证招生

DAMA认证为数据管理专业人士提供职业目标晋升规划&#xff0c;彰显了职业发展里程碑及发展阶梯定义&#xff0c;帮助数据管理从业人士获得企业数字化转型战略下的必备职业能力&#xff0c;促进开展工作实践应用及实际问题解决&#xff0c;形成企业所需的新数字经济下的核心职业…...

KMP 算法(Knuth-Morris-Pratt)

tip&#xff1a;作为程序员一定学习编程之道&#xff0c;一定要对代码的编写有追求&#xff0c;不能实现就完事了。我们应该让自己写的代码更加优雅&#xff0c;即使这会费时费力。 推荐&#xff1a;体系化学习Java&#xff08;Java面试专题&#xff09; 文章目录 一、什么是 …...

Java泛型详解

泛型的理解 泛型的概念 所谓泛型&#xff0c;就是允许在定义类、接口时通过一个标识表示类中某个属性的类型 或者是 某个方法的返回值类型及参数类型。这个类型参数将在使用时&#xff08;例如&#xff0c;继承或实现这个接口&#xff0c;用这个类型声明变量、创建对象时&#…...

2023上海国际嵌入式展 | 如何通过人工智能驱动的自动化测试工具提升嵌入式开发效率

2023年6月14日到16日&#xff0c;龙智将在2023上海国际嵌入式展&#xff08;embedded world China 2023&#xff09;A055展位亮相。同时&#xff0c;6月14日下午3:00-3:30&#xff0c;龙智资深DevSecOps顾问巫晓光将于创新技术及应用发展论坛第二论坛区&#xff08;A325展位&am…...

微信小程序个人心得

首先从官方文档给的框架说起,微信小程序官方文档给出了app.js, app.json, app.wxss. 先从这三个文件说起. 复制 app.js 这个文件是整个小程序的入口文件,开发者的逻辑代码在这里面实现,同时在这个文件夹里面可以定义全局变量.app.json 这个文件可以对小程序进行全局配置,决定…...

苹果MacOS系统傻瓜式本地部署AI绘画Stable Diffusion教程

Stable Diffusion的部署对小白来说非常麻烦&#xff0c;特别是又不懂技术的人。今天分享两个一键傻瓜式安装包&#xff0c;对小白来说非常有用。下面两个任选一个安装就可以。 一、DiffusionBee 简单介绍 DiffusionBee是基于stable diffusion的一个安装包&#xff0c;有图形…...

DBA之路-- 闪回恢复区FRA(Flash recovery area)与闪回特性(flashback)[待更新]

闪回恢复区FRA&#xff08;Flash recovery area&#xff09;与闪回特性&#xff08;flashback&#xff09; 1、闪回特性FB 用于快速简单恢复数据库中出现的认为误操作等逻辑错误 Flashback由undo表空间的撤销段内容为基础&#xff0c;受限于UNDO_RETENTON参数。要使用flashb…...

chatgpt赋能python:Python3.6.5到Python3.7.5:升级指南

Python 3.6.5到Python 3.7.5&#xff1a;升级指南 Python是一种广泛使用的编程语言&#xff0c;拥有强大的库和框架&#xff0c;能够开发各种类型的应用程序。在Python的发行版中&#xff0c;版本更新是常见的过程&#xff0c;以提供更好的性能和新的功能。 本文将介绍如何将…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

2021-03-15 iview一些问题

1.iview 在使用tree组件时&#xff0c;发现没有set类的方法&#xff0c;只有get&#xff0c;那么要改变tree值&#xff0c;只能遍历treeData&#xff0c;递归修改treeData的checked&#xff0c;发现无法更改&#xff0c;原因在于check模式下&#xff0c;子元素的勾选状态跟父节…...

多种风格导航菜单 HTML 实现(附源码)

下面我将为您展示 6 种不同风格的导航菜单实现&#xff0c;每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

SpringTask-03.入门案例

一.入门案例 启动类&#xff1a; package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

QT3D学习笔记——圆台、圆锥

类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体&#xff08;对象或容器&#xff09;QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质&#xff08;定义颜色、反光等&#xff09;QFirstPersonC…...

关于uniapp展示PDF的解决方案

在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项&#xff1a; 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库&#xff1a; npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...

日常一水C

多态 言简意赅&#xff1a;就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过&#xff0c;当子类和父类的函数名相同时&#xff0c;会隐藏父类的同名函数转而调用子类的同名函数&#xff0c;如果要调用父类的同名函数&#xff0c;那么就需要对父类进行引用&#…...