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

JAVA- AOP 面向切面编程 Aspect切面工具类 记录特定方法执行时的入参、执行时间、返参等内容

背景:JAVA项目,使用AOP对指定函数进行切面。能够记录特定方法执行时的入参、执行时间、返参结果等内容。

文章目录

    • 1、自定义注解类
      • 1.1 @Target
      • 1.2 @Retention
    • 2、Aspect切面工具
      • 2.1 JointPoint
      • 2.2 @Pointcut
      • 2.3 切面中的相关注解
    • 3、同一个类里调用AOP
    • 4、其他可获取参数

AOP可以实现对于函数执行整个过程中的数据流信息流,
比如调用函数方法前,需要根据头部信息来调用外部接口获取到所需的信息,来决定后续方法执行的逻辑;调用函数方法后,日志信息的记录(请求参数、返回结果、执行时长等)。

1、自定义注解类

可以在需要使用的函数上加上对应注解即可使用,不会将AOP应用于全部的函数。
例如这儿名为AutoLog,后续只需要在对应所需函数上使用@AutoLog即可

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 自定义注解类,在对应的函数上使用@AutoLog即可*/@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上
@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行
//@Documented //生成文档
public @interface AutoLog {String value() default "";
}

1.1 @Target

@Target 说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。
  作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)

取值(ElementType)有:
    1.CONSTRUCTOR:用于描述构造器
    2.FIELD:用于描述域
    3.LOCAL_VARIABLE:用于描述局部变量
    4.METHOD:用于描述方法
    5.PACKAGE:用于描述包
    6.PARAMETER:用于描述参数
    7.TYPE:用于描述类、接口(包括注解类型) 或enum声明

1.2 @Retention

@Retention(RetentionPolicy.RUNTIME) 注解按生命周期来划分可分为3类:

1、RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;
2、RetentionPolicy.CLASS:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期;
3、RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;

这3个生命周期分别对应于:Java源文件(.java文件) —> .class文件 —> 内存中的字节码。

那怎么来选择合适的注解生命周期呢?

首先要明确生命周期长度 SOURCE < CLASS < RUNTIME ,所以前者能作用的地方后者一定也能作用。一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解;如果要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife),就用 CLASS注解;如果只是做一些检查性的操作,比如 @Override 和 @SuppressWarnings,则可选用 SOURCE 注解。

2、Aspect切面工具

2.1 JointPoint

JointPoint是程序运行过程中可识别的点,这个点可以用来作为AOP切入点。JointPoint对象则包含了和切入相关的很多信息。比如切入点的对象,方法,属性等。我们可以通过反射的方式获取这些点的状态和信息,用于追踪tracing和记录logging应用信息。

2.2 @Pointcut

通过@Pointcut定义切入点,可作用于全部方法或指定方法
execution:用于匹配方法执行的连接点
@annotation:用于匹配当前执行方法持有指定注解的方法

//作用于service中所有方法
@Pointcut("execution(* com.demo.service.*(..))")//作用与所有接口
@Pointcut("execution( public * com.demo.controller.*Controller.*(..))")//作用与加了注解的指定接口,注解形式配置参考第1部分
@Pointcut("@annotation( com.demo.utils.AutoLog)")

2.3 切面中的相关注解

@Before 定义了一个前置通知,是在所拦截方法执行之前执行一段逻辑。
@After 是在所拦截方法执行之后执行一段逻辑。
@Around 是可以同时在所拦截方法的前后执行一段逻辑。
@AfterReturning 是可以获取该执行方法的返回值。
@AfterThrowing 定义了一个异常通知,若方法抛出了Exception类型的异常,都会回调afterThrowing方法。

Aspect切面工具类如下:

import com.demo.services.AutoTestLogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;import org.aspectj.lang.annotation.Aspect;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;@Aspect
@Component
@Slf4j
public class AutoTestLogAspect {long startTime;String body;@Autowiredprivate AutoTestLogService autoTestLogService;//作用于所有接口//@Pointcut("execution( public * com.demo.controller.*Controller.*(..))")//定义切点 @Pointcut 在注解的位置切入代码 指定注解@Pointcut("@annotation( com.demo.utils.AutoLog)")@Before("logPointCut()")public void doBefore(JoinPoint joinPoint) {//开始时间startTime = System.currentTimeMillis();//获取入参Object[] objects= joinPoint.getArgs();//将数组转成Stringbody = Arrays.toString(objects);}@After("logPointCut()")public void doAfter() {long spendTime = System.currentTimeMillis() - startTime;log.info("spendTime:" + spendTime + "ms");}//切面 配置通知@AfterReturning(returning = "object", pointcut = "logPointCut()")public void doAfterReturning(Object object) {long spendTime = System.currentTimeMillis() - startTime;log.info("response={}", object.toString());//将被调用记录插入数据库autoTestLogService.insertAutoTestData(spendTime,true, object.toString());}@AfterThrowing(value = "logPointCut()", throwing = "exception")public void doAfterThrowingAdvice(JoinPoint joinPoint, Exception exception){ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();long spendTime = System.currentTimeMillis() - startTime;if (requestAttributes != null) {HttpServletRequest request = requestAttributes.getRequest();//记录请求方法log.info("REQUEST: {}", request.getMethod());log.info("REQUEST_METHOD: {}", joinPoint.getSignature());//异常信息log.info("EXCEPTION: {}", exception.getMessage());}}@Around("logPointCut()")public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {long start = System.currentTimeMillis();try {Object result = joinPoint.proceed();long end = System.currentTimeMillis();log.error("around " + joinPoint + "\tUse time : " + (end - start) + " ms!");return result;} catch (Throwable e) {long end = System.currentTimeMillis();log.error("around " + joinPoint + "\tUse time : " + (end - start) + " ms with exception : " + e.getMessage());throw e;}}
}

主要作用是在于记录切面获取的信息,比如执行方法入参、传参、返参等等。
service

import com.demo.dao.mapper.AutoTestLogMapper;
import com.demo.dao.po.AutoTestLog;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;import java.util.Date;@Slf4j
@Service
public class AutoTestLogService {@AutowiredAutoTestLogMapper autoTestLogMapper;/*** 埋点数据落表* @return*/@Async("taskExecutor")public Boolean insertAutoTestData(double spendingTime, boolean isSuccess, Object object){Gson gson = new Gson();AutoTestLog autoTestLog = new AutoTestLog();autoTestLog.setSpendTime(spendingTime);autoTestLog.setSuccess(isSuccess);autoTestLog.setCreateDate(new Date());autoTestLog.setUpdatedDate(new Date());autoTestLog.setResponse(object.toString());try {autoTestLogMapper.insert(autoTestLog);log.info(String.format("AOP调用结果:%s", gson.toJson(autoTestLog)));}catch (Exception e){log.error(e.getMessage());return false;}return true;}}

定义PO

import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;import java.io.Serializable;
import java.util.Date;@Data
@TableName("auto_log")
public class AutoTestLog implements Serializable {@TableId(type = IdType.AUTO)private Integer id;@TableField(value = "is_success")private boolean isSuccess;@TableField(value = "response")private String response;@TableField(value = "spend_time")private double spendTime;@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+08:00")@TableField(value = "create_date",fill = FieldFill.INSERT)private Date createDate;@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+08:00")@TableField(value = "updated_date",fill = FieldFill.UPDATE)private Date updatedDate;
}

mapper

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.demo.dao.po.AutoTestLog;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Component;@Mapper
@Component
public interface AutoTestLogMapper extends BaseMapper<AutoTestLog> {
}

sql

DROP TABLE IF EXISTS `auto_log`;
CREATE TABLE `auto_log` (`id` int NOT NULL AUTO_INCREMENT,`is_success` tinyint DEFAULT NULL COMMENT '判断升级是否成功;0:失败;1:成功',`response` varchar(500) COMMENT '请求结果',`spend_time` DOUBLE(16,2) DEFAULT '0' COMMENT '接口耗时',`create_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,`updated_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY (`id`)INDEX (is_success)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

3、同一个类里调用AOP

需要在启动类加上该注解,其会往容器中注入了AnnotationAwareAspectJAutoProxyCreator组件,该组件就是AOP的核心

@EnableAspectJAutoProxy(exposeProxy=true)

具体service中内容如下:
getservice()为了解决事务失效,注入bean;
demo()就是我们切面记录方法;
exec()就是业务函数,在其中用事务方式调用AOP方法即可。

//解决事务失效private xxService getService(){return SpringUtil.getBean(this.getClass());}public exec{//需要执行的AOP函数getService.demo();}@AutoLog("synAutoTestLog")public String demo(){//业务代码}

4、其他可获取参数

可获取执行过程中的诸多参数,例如:
前置操作中参数,例如请求URL、请求IP、请求类名、请求方法名、请求参数等
执行后的返回值、请求耗时、浏览器类型、操作系统、header等

package com.xkcoding.log.aop.aspectj;import java.io.BufferedReader;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;import javax.servlet.http.HttpServletRequest;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import cn.hutool.json.JSONUtil;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;@Aspect
@Component
@Slf4j
public class AopLog {private static final String START_TIME = "request-start";/*** 切入点*/@Pointcut("xxx")public void log() {}/*** 前置操作** @param point 切入点*/@Before("log()")public void beforeLog(JoinPoint point) {ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();log.info("请求 URL:{}", request.getRequestURL());log.info("请求 IP:{}", request.getRemoteAddr());log.info("请求类名:{},请求方法名:{}", point.getSignature().getDeclaringTypeName(), point.getSignature().getName());log.info("body:{},", JSONUtil.toJsonStr(point.getArgs()));Map<String, String[]> parameterMap = request.getParameterMap();log.info("请求参数:{},", JSONUtil.toJsonStr(parameterMap));Long start = System.currentTimeMillis();request.setAttribute(START_TIME, start);}/*** 环绕操作** @param point 切入点* @return 原方法返回值* @throws Throwable 异常信息*/@Around("log()")public Object aroundLog(ProceedingJoinPoint point) throws Throwable {Object result = point.proceed();log.info("返回值:{}", JSONUtil.toJsonStr(result));return result;}/*** 后置操作*/@AfterReturning("log()")public void afterReturning() {ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();Long start = (Long) request.getAttribute(START_TIME);Long end = System.currentTimeMillis();log.info("请求耗时:{}毫秒", end - start);String header = request.getHeader("User-Agent");UserAgent userAgent = UserAgent.parseUserAgentString(header);log.info("浏览器类型:{},操作系统:{},原始User-Agent:{}", userAgent.getBrowser().toString(), userAgent.getOperatingSystem().toString(), header);}
}

参考:
https://blog.csdn.net/zhangting19921121/article/details/124351092
https://my.oschina.net/lizaizhong/blog/1611165
https://blog.csdn.net/weixin_44195615/article/details/113650701
https://blog.csdn.net/qq_18671415/article/details/111866546
https://blog.csdn.net/mameng1988/article/details/85548812
https://blog.csdn.net/Weixiaohuai/article/details/122494670

相关文章:

JAVA- AOP 面向切面编程 Aspect切面工具类 记录特定方法执行时的入参、执行时间、返参等内容

背景&#xff1a;JAVA项目&#xff0c;使用AOP对指定函数进行切面。能够记录特定方法执行时的入参、执行时间、返参结果等内容。 文章目录1、自定义注解类1.1 Target1.2 Retention2、Aspect切面工具2.1 JointPoint2.2 Pointcut2.3 切面中的相关注解3、同一个类里调用AOP4、其他…...

「史上最全的 TCG 规范解读」TCG 规范架构概述(下)

可信计算组织&#xff08;Ttrusted Computing Group,TCG&#xff09;是一个非盈利的工业标准组织&#xff0c;它的宗旨是加强不同计算机平台上计算环境的安全性。TCG 于 2003 年春成立&#xff0c;并采纳了由可信计算平台联盟&#xff08;the Trusted Computing Platform Allia…...

GDScript 导出变量 (4.0)

概述 导出变量的功能在3.x版本中也是有的&#xff0c;但是4.0版本对其进行了语法上的改进。 导出变量在日常的游戏制作中提供节点的自定义参数化调节功能时非常有用&#xff0c;除此之外还用于自定义资源。 本文是&#xff08;Bilibili巽星石&#xff09;在4.0官方文档《GDScr…...

JAVA知识点全面总结6:泛型反射和注解

六.JAVA知识点全面总结6泛型反射和注解 1.什么是泛型?可以用在哪里&#xff1f; 2.泛型擦除机制是什么&#xff1f;为什么擦除&#xff1f; 3.通配符是什么&#xff1f;作用是什么&#xff1f; 未更新 1.注解是什么&#xff1f;有什么用&#xff1f; 2.注解的自定义和实…...

死代码删除(DCE,Dead Code Elimination)和激进的死代码删除(ADCE,Aggressive DCE)

死代码删除&#xff08;DCE&#xff0c;Dead Code Elimination&#xff09;和激进的死代码删除&#xff08;ADCE&#xff0c;Aggressive DCE&#xff09;死代码删除&#xff08;DCE&#xff0c;Dead Code Elimination&#xff09;DCE简介DCE基本算法激进的死代码删除&#xff0…...

询问new bing关于android开发的15个问题(前景、未来、发展方向)

前言&#xff1a;new bing是基于chat-gpt的新搜索工具&#xff0c;可以采用对话方式进行问题搜索&#xff0c;经过排队等候终于可以使用new bing&#xff0c;询问了目前我最关心的关于android开发几个问题 文章目录1.如何学好android开发&#xff1f;2.android开发能做什么?3.…...

【C++】初识类和对象

&#x1f3d6;️作者&#xff1a;malloc不出对象 ⛺专栏&#xff1a;C的学习之路 &#x1f466;个人简介&#xff1a;一名双非本科院校大二在读的科班编程菜鸟&#xff0c;努力编程只为赶上各位大佬的步伐&#x1f648;&#x1f648; 目录前言一、面向过程和面向对象初步认识二…...

EPICS S7nodave手册

第一章&#xff1a;介绍 本手册分为6章(不算次介绍部分)。第一章介绍s7nodave用于EPICS的设备支持的概念和特新。第二章描述启动一个使用s7nodave的IOC项目所需要的几步。第三章描述s7nodave支持的IOC shell命令。之后&#xff0c;第四章解释s7nodave支持的各种记录类型。最后…...

2023最新版本RabbitMQ的持久化和简单使用

上节讲了 RabbitMQ下载安装教程 &#xff0c; 本节主要介绍RabbitMQ的持久化和简单使用。 一、RabbitMQ消息持久化 当处理一个比较耗时得任务的时候&#xff0c;也许想知道消费者&#xff08;consumers&#xff09;是否运行到一半就挂掉。在当前的代码中&#xff0c;当RabbitM…...

函数式编程

函数式编程&#xff08;一&#xff09; 文章目录函数式编程&#xff08;一&#xff09;1. 前言1.1 概念2. Lambda 表达式2.1 概述2.2 基本的格式2.3 触发条件2.4 Lambda表达式2.4.1 无参无返回值2.4.2 有参无返回值2.4.3 无参数有返回值2.4.4 有参有返回值【重点】2.4.4.1 比较…...

【Java 类】001-访问修饰符、命名规范

【Java 类】001-访问修饰符、命名规范 文章目录【Java 类】001-访问修饰符、命名规范一、访问修饰符概述1、是什么2、作用作用问题3、访问修饰符有哪些4、作用对象二、访问修饰符使用演示1、类访问修饰符演示第一步&#xff1a;创建 Dog 类&#xff1a;public第二步&#xff1a…...

【C++】命名空间

&#x1f3d6;️作者&#xff1a;malloc不出对象 ⛺专栏&#xff1a;C的学习之路 &#x1f466;个人简介&#xff1a;一名双非本科院校大二在读的科班编程菜鸟&#xff0c;努力编程只为赶上各位大佬的步伐&#x1f648;&#x1f648; 目录前言一、命名空间产生的背景二、命名空…...

【AutoSAR】【MCAL】Dio

一、结构 二、功能介绍 DIO&#xff08;数字输入输出&#xff09;驱动模块主要是对端口&#xff08;Port&#xff09;&#xff0c;通道&#xff08;Channel&#xff09;和通道组&#xff08;ChannelGroup&#xff09;进行读写操作。 通道&#xff08;Channel&#xff09;&…...

瑞吉外卖——day2

目录 一、新增员工 二、查询分页数据 三、启用、禁用员工账户、编辑员工信息 一、新增员工 点击左上角新增员工 页面如下&#xff1a; 我们随便填数据 &#xff0c;点击保存&#xff0c;请求的地址如下 返回前端可以看到请求方式为Post 在employeeController中编写对应的代…...

了解java

#常见编程语言介绍 C语言 C语言 java语言 javaScript语言 PHP语言 python语言Object-C和Swift语言 C# &#xff08;c sharp&#xff09;语言 Kotlin语言 Go语言 Basic语言 #JAVA的发展 起源于1991年SUN公司GREEN项目&#xff0c;1996年JDK1.0正式发布 后被Oracle公司收购&…...

【编程实践】代码之中有创意:“我一直认为工程师世界上最具创造性的工作之一”

代码之中有创意 “我一直认为工程师世界上最具创造性的工作之一”。 文章目录 代码之中有创意一、代码可以赋予创造力1.1 代码的创造力1.2 如何发挥代码的创造力二、有创意的代码可以提高工作效率2.1 代码创意可以提高工作效率2.2 如何利用代码创意来提高工作效率三、代码创意可…...

【MySQL】表连接

一、为什么要学习 因为不合理的使用连接会导致慢查询 二、什么是连接 参与连接的表叫做 连接表&#xff0c; 连接就是把 各个连接表 进行的组合 &#xff08;笛卡儿积&#xff09;加入结果集并返回 三、连接查询 如何只是对表进行大量的连接&#xff0c;笛卡儿积作用得到的…...

2023湖南省“楚怡杯”职业技能大赛“网络安全” 项目比赛任务书

2023湖南省“楚怡杯”职业技能大赛“网络安全” 项目比赛任务书2023安徽省“中银杯”职业技能大赛“网络安全” 项目比赛任务书A模块基础设施设置/安全加固&#xff08;200分&#xff09;A-1&#xff1a;登录安全加固&#xff08;Windows, Linux&#xff09;A-2&#xff1a;Ngi…...

Android应用启动优化笔记整理

应用启动相关流程与优化 应用启动主要涉及SystemServer进程 和 app进程。 SystemServer进程负责app进程创建和管理、窗口的创建和管理&#xff08;StartingWindow 和 AppWindow&#xff09;、应用的启动流程调度等。 App进程被创建后&#xff0c;进行一系列进程初始化、组件初…...

图像bytes字节串二进制转十六进制及bytes转为图像

目录前言正文二进制与十六进制的bytes互转读取bytes为图像法1:直接写入f.read的结果法2: 转换为PIL或Numpy前言 参考&#xff1a; 8. python基础之基础数据类型–bytes - CSDN python 16进制与图片互转 - CSDN 正文 二进制与十六进制的bytes互转 bytes保存的是原始的字节(二…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)

骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术&#xff0c;它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton)&#xff1a;由层级结构的骨头组成&#xff0c;类似于人体骨骼蒙皮 (Mesh Skinning)&#xff1a;将模型网格顶点绑定到骨骼上&#xff0c;使骨骼移动…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

大数据学习(132)-HIve数据分析

​​​​&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4…...

LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》

这段 Python 代码是一个完整的 知识库数据库操作模块&#xff0c;用于对本地知识库系统中的知识库进行增删改查&#xff08;CRUD&#xff09;操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 &#x1f4d8; 一、整体功能概述 该模块…...

【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)

LeetCode 3309. 连接二进制表示可形成的最大数值&#xff08;中等&#xff09; 题目描述解题思路Java代码 题目描述 题目链接&#xff1a;LeetCode 3309. 连接二进制表示可形成的最大数值&#xff08;中等&#xff09; 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...