Spring实现输出带动态标签的日志

版权说明: 本文由博主keep丶原创,转载请保留此块内容在文首。
原文地址: https://blog.csdn.net/qq_38688267/article/details/144851857

文章目录

    • 背景
    • 底层原理
    • 实现方案
      • Tag缓存实现
      • 封装注解通过AOP实现日志缓存
      • 封装行为参数通用方法实现
      • 手动缓存Tag值
    • 整理代码,封装通用LogHelper类

背景

  部分业务代码会被多个模块调用,此时该部分代码输出的日志无法直观看出是从哪个模块调用的,因此提出动态标签日志需求,效果如下:
在这里插入图片描述

底层原理

  业务代码起始时通过ThreadLocal存储当前业务标签值,后续日志输出时,插入缓存的业务标签到输出的日志中。即可实现该需求。

实现方案

Tag缓存实现


    private static final ThreadLocal<String> logTagCache = new ThreadLocal<>();

    /**
     * 获取缓存的标签值
     * <b style="color:red">只有添加了@BizLog注解的方法内才可用</b>
     */
    static String getCacheTag() {
        String temp = logTagCache.get();
        if (temp == null) {
            log.warn("[LogHelper] 缓存标签为空, 请及时配置@BizLog注解或手动缓存标签.");
            return DEFAULT_TAG;
        }
        return temp;
    }

    static void cacheTag(String logTag) {
        logTagCache.set(logTag);
    }

    /**
     * 清空当前线程缓存
     * <br/>
     * <b>使用set()或init()之后,请在合适的地方调用clean(),一般用try-finally语法在finally块中调用</b>
     */
    static void cleanCache() {
        logTagCache.remove();
    }

封装注解通过AOP实现日志缓存

  • 注解定义
/**
 * 启动业务日志注解
 *
 * @author zeng.zf
 */
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface BizLog {

    /**
     * 日志标签值
     * <p>
     * 如果不给值则默认输出类型方法名,给值用给的值<br/>
     * <b>会缓存标签值,可使用{@code LogHelper.xxxWCT()}方法</b>
     * @see cn.xxx.log.util.LogHelper.WCT#catchLog(Logger, Runnable)
     * @see cn.xxx.log.util.LogHelper.WCT#log(String, Object...) 
     */
    String value();
}
  • AOP切面配置
/**
 * {@link BizLog} 切面,记录业务链路
 *
 * @author zzf
 */
@Aspect
@Order// 日志的AOP逻辑放最后执行
public class BizLogAspect {

    @Around("@annotation(bizLog)")
    public Object around(ProceedingJoinPoint joinPoint, BizLog bizLog) throws Throwable {
        try {
	        LogHelper.UTIL.cacheTag(bizLog.value());
            return joinPoint.proceed();
        }  finally {
            LogHelper.UTIL.cleanCache();
        }
    }

封装行为参数通用方法实现

        /**
         * 缓存给定tag后执行给定方法<br/>
         * 使用:{@code LogHelper.beginTrace("AddUser", () -> userService.addUser(user))}
         *
         * @param tag      日志标签
         * @param runnable 执行内容
         */
        static void beginTrace(String tag, Runnable runnable) {
            try {
                cacheTag(tag);
                runnable.run();
            } finally {
                cleanCache();
            }
        }

        /**
         * 缓存给定tag后执行给定方法<br/>
         * 使用:{@code return LogHelper.beginTrace("AddUser", () -> userService.addUser(user))}
         *
         * @param tag      日志标签
         * @param supplier 有返回值的执行内容
         */
        static <T> T beginTrace(String tag, Supplier<T> supplier) {
            try {
                cacheTag(tag);
                return supplier.get();
            } finally {
                cleanCache();
            }
        }

手动缓存Tag值

  • 非Bean方法可通过手动调用LogHelper.UTIL.beginTrace()方法实现@BizLog相同功能。
  • 也可以参考方法手写cacheTag()和cleanCache()实现该功能。
    • 一般不建议这么做,使用工具类方法最好。
    • 如果runnable参数会抛异常的情况下就不适合用工具方法,此时可以手写。
    • 手写时必须使用try-finally块,并在finally块中调用cleanCache()。
      在这里插入图片描述

整理代码,封装通用LogHelper类


/**
 * 日志输出辅助类
 * <br/>
 * 注意:所有格式化参数在格式化时都是调用其toString()方法<br/>
 * 因此对象需要重写toString()方法或者使用{@code JSONUtil.toJsonStr()}转成JSON字符串。<br/>
 * <br/>
 * <b>如果自行输出日志,请按照该格式: {@code "[TAG][SUB_TAG] CONTENT"}</b>
 * <p>如: 1. {@code "[AddUser] add success"}</p>
 * <p>&emsp;&emsp;2. {@code "[AddUser][GenRole] add success"}</p>
 * <p>&emsp;&emsp;2. {@code "[AddUser][BizException] 用户名重复"}</p>
 * <p>更多请参考源文件中的LogHelperTest测试类</p>
 */
@Slf4j
public class LogHelper {

    /**
     * 缓存{@link cn.xxx.log.core.aop.log.BizLog} 注解的value值
     */
    private static final ThreadLocal<String> logTagCache = new ThreadLocal<>();

    private static final String DEFAULT_TAG = "TAG_NOT_CONFIG";

    /*===========以下为工具方法,提供Tag缓存相关方法============*/
    public interface UTIL {

        /**
         * 缓存给定tag后执行给定方法<br/>
         * 使用:{@code LogHelper.beginTrace("AddUser", () -> userService.addUser(user))}
         *
         * @param tag      日志标签
         * @param runnable 执行内容
         */
        static void beginTrace(String tag, Runnable runnable) {
            try {
                cacheTag(tag);
                runnable.run();
            } finally {
                cleanCache();
            }
        }

        /**
         * 缓存给定tag后执行给定方法<br/>
         * 使用:{@code return LogHelper.beginTrace("AddUser", () -> userService.addUser(user))}
         *
         * @param tag      日志标签
         * @param supplier 有返回值的执行内容
         */
        static <T> T beginTrace(String tag, Supplier<T> supplier) {
            try {
                cacheTag(tag);
                return supplier.get();
            } finally {
                cleanCache();
            }
        }

        /**
         * 缓存给定tag后执行给定方法,提供默认异常处理<br/>
         * 使用:{@code LogHelper.catchBeginTrace(log, "AddUser", () -> userService.addUser(user))}
         *
         * @param tag      日志标签
         * @param runnable 执行内容
         */
        static void catchBeginTrace(Logger logger, String tag, Runnable runnable) {
            try {
                cacheTag(tag);
                WCT.catchLog(logger, runnable);
            } finally {
                cleanCache();
            }
        }

        /**
         * 缓存给定tag后执行给定方法,提供默认异常处理<br/>
         * 使用:{@code return LogHelper.catchBeginTrace(log, "AddUser", () -> userService.addUser(user))}
         *
         * @param tag      日志标签
         * @param supplier 有返回值的执行内容
         */
        static <T> @Nullable T catchBeginTrace(Logger logger, String tag, Supplier<T> supplier) {
            try {
                cacheTag(tag);
                return WCT.catchLog(logger, supplier);
            } finally {
                cleanCache();
            }
        }

        /**
         * 获取缓存的标签值
         * <b style="color:red">只有添加了@BizLog注解的方法内才可用</b>
         */
        static String getCacheTag() {
            String temp = logTagCache.get();
            if (temp == null) {
                log.warn("[LogHelper] 缓存标签为空, 请及时配置@BizLog注解或手动缓存标签.");
                return DEFAULT_TAG;
            }
            return temp;
        }

        static void cacheTag(String logTag) {
            logTagCache.set(logTag);
        }

        /**
         * 清空当前线程缓存
         * <br/>
         * <b>使用set()或init()之后,请在合适的地方调用clean(),一般用try-finally语法在finally块中调用</b>
         */
        static void cleanCache() {
            logTagCache.remove();
        }
    }


    /*=========================以下为基础方法,提供基础日志输出方法=======================*/
    public interface BASIC {

        /**
         * 标签日志<br/>
         * 例:
         * {@code LogHelper.tag("AddUser", "GenRole", "add success, user id = {}, name = {}", 1L, "zs")}<br/>
         * 返回 {@code "[AddUser][GenRole] add success, user id = 1, name = zs"}
         *
         * @param tag     标签
         * @param content 需要格式化内容
         * @param arg     格式化参数
         * @return 最终日志
         */
        static String tag(String tag, String content, Object... arg) {
            return StrUtil.format("[{}] {}", tag, StrUtil.format(content, arg));
        }

        /**
         * 两级标签日志<br/>
         * 例:
         * {@code LogHelper.tag("AddUser", "GenRole", "add success")}<br/>
         * 返回 {@code "[AddUser][GenRole] add success"}
         *
         * @param tag     标签
         * @param subTag  子标签
         * @param content 内容
         * @return 最终日志
         */
        static String doubleTag(String tag, String subTag, String content, Object... args) {
            return StrUtil.format("[{}][{}] {}", tag, subTag, StrUtil.format(content, args));
        }

        /**
         * 业务异常tag日志内容生成
         */
        static String bizExTag(String tag, BizExceptionMark bizException) {
            return StrUtil.format("[{}][{}] code={},msg={}", tag, bizException.getClass().getSimpleName(),
                                  bizException.getCode(), bizException.getMsg());
        }

        /**
         * 业务异常tag日志内容生成
         */
        static String bizExTag(String tag, BizExceptionMark bizException, String extraInfo, Object... args) {
            return StrUtil.format("[{}][{}] code={},msg={}, extraInfo={{}}", tag,
                                  bizException.getClass().getSimpleName(), bizException.getCode(),
                                  bizException.getMsg(), StrUtil.format(extraInfo, args));
        }

        /**
         * 业务异常tag日志内容生成
         */
        static String bizEx(BizExceptionMark bizException) {
            return StrUtil.format("[{}] code={},msg={}", bizException.getClass().getSimpleName(),
                                  bizException.getCode(), bizException.getMsg());
        }

        /**
         * 运行时异常tag日志内容生成
         */
        static String otherExTag(String tag, Exception e) {
            return StrUtil.format("[{}][{}] msg={}, stackTrace={}", tag, e.getClass().getSimpleName(), e.getMessage(),
                                  TraceUtils.getStackTraceStr(e.getStackTrace()));
        }

        /**
         * 运行时异常tag日志内容生成
         */
        static String otherExTag(String tag, Exception e, String extraInfo, Object... args) {
            return StrUtil.format("[{}][{}] msg={}, extraInfo={{}}, stackTrace={}", tag, e.getClass().getSimpleName(),
                                  e.getMessage(), StrUtil.format(extraInfo, args),
                                  TraceUtils.getStackTraceStr(e.getStackTrace()));
        }

        /**
         * 其他异常tag日志内容生成
         */
        static String otherEx(Exception e) {
            return StrUtil.format("[{}] msg={}, stackTrace={}", e.getClass().getSimpleName(), e.getMessage(),
                                  TraceUtils.getStackTraceStr(e.getStackTrace()));
        }

        /**
         * 通用标签日志包装<br/>
         * <p>使用案例:</p>
         * 1. {@code tagLogWrap(() -> bizMethod(param1, param2))}<br/>
         * 2.
         * <pre><code>
         * \@Slf4j
         * public class UserServiceImpl{
         *
         *     public void addUsers(List<User> users) {
         *          for(user in users) {
         *              LogHelper.tagLogWrap(log, "AddUsers", () -> addUser(user));
         *          }
         *     }
         *     public void addUser(User user) {
         *         xxx
         *         xxx
         *         ...
         *     }
         * }
         * </code></pre>
         *
         * @param tag      日志标签
         * @param runnable 你要执行的无返回值方法
         */
        static void catchLog(Logger logger, String tag, Runnable runnable) {
            try {
                runnable.run();
            } catch (Exception e) {
                if (e instanceof BizExceptionMark) {
                    logger.warn(bizExTag(tag, (BizExceptionMark) e));
                } else {
                    logger.error(otherExTag(tag, e));
                }
            }
        }

        /**
         * 通用标签日志包装<br/>
         * <p>使用案例:</p>
         * 1. {@code tagLogWrap(() -> bizMethod(param1, param2))}<br/>
         * 2.
         * <pre><code>
         * \@Slf4j
         * public class UserServiceImpl{
         *
         *     public void addUsers(List<User> users) {
         *          for(user in users) {
         *              LogHelper.tagLogWrap(
         *                  log,
         *                  "AddUsers",
         *                  () -> addUser(user),
         *                  "id = {}, name={}",
         *                  user.getId(),
         *                  user.getName()
         *                  );
         *          }
         *     }
         *     public void addUser(User user) {
         *         xxx
         *         xxx
         *         ...
         *     }
         * }
         * </code></pre>
         *
         * @param tag      日志标签
         * @param runnable 你要执行的无返回值方法
         */
        static void catchLog(Logger logger, String tag, Runnable runnable, String extraInfo, Object... args) {
            try {
                runnable.run();
            } catch (Exception e) {
                if (e instanceof BizExceptionMark) {
                    logger.warn(bizExTag(tag, (BizExceptionMark) e, extraInfo, args));
                } else {
                    logger.error(otherExTag(tag, e, extraInfo, args));
                }
            }
        }

        /**
         * 通用标签日志包装<br/>
         * <p>使用案例:</p>
         * 1. {@code return tagLogWrap(() -> bizMethod(param1, param2))}<br/>
         * 2.
         * <pre><code>
         * \@Slf4j
         * public class UserServiceImpl{
         *
         *     public List<User> getUserByIds(List<Long> ids) {
         *          return ids.map(id ->
         *              LogHelper.tagLogWrap(log, "getUserByIds", () -> getUserById(id))
         *          ).collect(Collectors.toList());
         *     }
         *     public User getUserById(Long userId) {
         *         xxx
         *         xxx
         *         ...
         *         return user;
         *     }
         * }
         * </code></pre>
         *
         * @param tag      日志标签
         * @param supplier 你要执行的有返回值方法
         * @return 方法执行结果(可能为null)
         */
        static <R> @Nullable R catchLog(Logger logger, String tag, Supplier<R> supplier) {
            try {
                return supplier.get();
            } catch (Exception e) {
                if (e instanceof BizExceptionMark) {
                    logger.warn(bizExTag(tag, (BizExceptionMark) e));
                } else {
                    logger.error(otherExTag(tag, e));
                }
            }
            return null;
        }

        /**
         * 通用标签日志包装<br/>
         * <p>使用案例:</p>
         * 1. {@code return tagLogWrap(() -> bizMethod(param1, param2))}<br/>
         * 2.
         * <pre><code>
         * \@Slf4j
         * public class UserServiceImpl{
         *
         *     public List<User> getUserByIds(List<Long> ids) {
         *          return ids.map(id ->
         *              LogHelper.tagLogWrap(
         *                  log,
         *                  "getUserByIds",
         *                  () -> getUserById(id),
         *                  "id={}",
         *                  id
         *                  )
         *          ).collect(Collectors.toList());
         *     }
         *     public User getUserById(Long userId) {
         *         xxx
         *         xxx
         *         ...
         *         return user;
         *     }
         * }
         * </code></pre>
         *
         * @param tag      日志标签
         * @param supplier 你要执行的有返回值方法
         * @return 方法执行结果(可能为null)
         */
        static <R> @Nullable R catchLog(Logger logger, String tag, Supplier<R> supplier, String extraInfo,
                                        Object... args) {
            try {
                return supplier.get();
            } catch (Exception e) {
                if (e instanceof BizExceptionMark) {
                    logger.warn(bizExTag(tag, (BizExceptionMark) e, extraInfo, args));
                } else {
                    logger.error(otherExTag(tag, e, extraInfo, args));
                }
            }

            return null;
        }
    }


    /*===================以下为基于缓存标签的方法,理论上上方基础方法都要在下面有对应的方法==================*/
    /* WCT = with cached tag */
    public interface WCT {

        /**
         * <b style="color:red">只有添加了@BizLog注解的方法内才可用</b>
         */
        static String log(String content, Object... args) {
            return BASIC.tag(getCacheTag(), content, args);
        }

        /**
         * <b style="color:red">只有添加了@BizLog注解的方法内才可用</b>
         */
        static String sub(String subTag, String content, Object... args) {
            return BASIC.doubleTag(getCacheTag(), subTag, content, args);
        }


        /**
         * 业务异常tag日志内容生成
         * <b style="color:red">只有添加了@BizLog注解的方法内才可用</b>
         */
        static String bizEx(BizExceptionMark bizException) {
            return BASIC.bizExTag(getCacheTag(), bizException);
        }

        /**
         * 业务异常tag日志内容生成
         * <b style="color:red">只有添加了@BizLog注解的方法内才可用</b>
         */
        static String bizEx(BizExceptionMark bizException, String extraInfo, Object... args) {
            return BASIC.bizExTag(getCacheTag(), bizException, extraInfo, args);
        }


        /**
         * 运行时异常tag日志内容生成
         * <b style="color:red">只有添加了@BizLog注解的方法内才可用</b>
         */
        static String otherEx(Exception e) {
            return BASIC.otherExTag(getCacheTag(), e);
        }


        /**
         * 运行时异常tag日志内容生成
         * <b style="color:red">只有添加了@BizLog注解的方法内才可用</b>
         */
        static String otherEx(String tag, Exception e, String extraInfo, Object... args) {
            return BASIC.otherExTag(tag, e, extraInfo, args);
        }


        /**
         * 通用标签日志包装<br/>
         * <b style="color:red">只有添加了@BizLog注解的方法内才可用</b>
         *
         * @param runnable 你要执行的无返回值方法
         */
        static void catchLog(Logger logger, Runnable runnable) {
            BASIC.catchLog(logger, getCacheTag(), runnable);
        }

        /**
         * 通用标签日志包装<br/>
         * <b style="color:red">只有添加了@BizLog注解的方法内才可用</b>
         *
         * @param runnable 你要执行的无返回值方法
         */
        static void catchLog(Logger logger, Runnable runnable, String extraInfo, Object... args) {
            BASIC.catchLog(logger, getCacheTag(), runnable, extraInfo, args);
        }


        /**
         * 通用标签日志包装<br/>
         * <b style="color:red">只有添加了@BizLog注解的方法内才可用</b>
         *
         * @param supplier 你要执行的有返回值方法
         * @return 方法执行结果(可能为null)
         */

        static <R> @Nullable R catchLog(Logger logger, Supplier<R> supplier) {
            return BASIC.catchLog(logger, getCacheTag(), supplier);
        }


        /**
         * 通用标签日志包装<br/>
         * <b style="color:red">只有添加了@BizLog注解的方法内才可用</b>
         *
         * @param supplier 你要执行的有返回值方法
         * @return 方法执行结果(可能为null)
         */

        static <R> @Nullable R catchLog(Logger logger, Supplier<R> supplier, String extraInfo, Object... args) {
            return BASIC.catchLog(logger, getCacheTag(), supplier, extraInfo, args);
        }

    }
}

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

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

相关文章

1月第一讲:WxPython跨平台开发框架之前后端结合实现附件信息的上传及管理

1、功能描述和界面 前端&#xff08;wxPython GUI&#xff09;&#xff1a; 提供文件选择、显示文件列表的界面。支持上传、删除和下载附件。展示上传状态和附件信息&#xff08;如文件名、大小、上传时间&#xff09;。后端&#xff08;REST API 服务&#xff09;&#xff1a…

微服务SpringCloud分布式事务之Seata

视频教程&#xff1a;https://www.bilibili.com/video/BV16P63Y3ESq 效果演示 准备的微服务项目调用的链路如下&#xff1a; 文字描述&#xff1a; gateway模块接收到请求&#xff0c;并发送到order订单模块order订单模块接收到请求&#xff0c;新增一个订单数据后发送一个…

Solon 加入 GitCode:助力国产 Java 应用开发新飞跃

在当今数字化快速发展的时代&#xff0c;Java 应用开发框架不断演进&#xff0c;开发者们始终在寻找更快、更小、更简单的解决方案。近期&#xff0c;Solon 正式加入 GitCode&#xff0c;为广大 Java 开发者带来全新的开发体验&#xff0c;尤其是在国产应用开发进程中&#xff…

[实用指南]如何将视频从iPhone传输到iPad

概括 将视频从 iPhone 传输到 iPad 时遇到问题&#xff1f;您可能知道一种方法&#xff0c;但不知道如何操作。此外&#xff0c;您要传输的视频越大&#xff0c;完成任务就越困难。那么如何将视频从 iPhone 传输到 iPad&#xff0c;特别是当您需要发送大视频文件时&#xff1f…

【一起python】银行管理系统

文章目录 &#x1f4dd;计算机基础概念&#x1f320; 导入模块&#x1f320;定义input_card_info函数&#x1f320; 定义check_password函数&#x1f320;初始化用户字典和欢迎信息&#x1f309; 主循环&#x1f309;开户操作&#x1f309;查询操作&#x1f309;取款操作&#…

20241218-信息安全理论与技术复习题

20241218-信息安全理论与技术复习题 一、习题1 信息安全的基本属性是&#xff08;D )。 A、机密性 B、可用性 C、完整性 D、上面 3 项都是 “会话侦听和劫持技术” 是属于&#xff08;B&#xff09;的技术。 A、 密码分析还原 B、 协议漏洞渗透 C、 应用漏洞分析与渗透 D、 D…

音视频入门基础:MPEG2-PS专题(2)——使用FFmpeg命令生成ps文件

一、错误的命令 通过FFmpeg命令可以将mp4文件转换为ps文件&#xff0c;PS文件中包含PS流数据。 由于PS流/PS文件对应的FFInputFormat结构为&#xff1a; const FFInputFormat ff_mpegps_demuxer {.p.name "mpeg",.p.long_name NULL_IF_CONFIG_SMALL…

Unity is running as administrator解决办法

每次打开Unity项目都会有这个弹窗 解决办法&#xff1a; 打开本地安全策略 - 安全选项 &#xff0c;把 用户账户控制&#xff1a;以管理员批准模式运行所有管理员 用户账户控制&#xff1a;用于内置管理员账户的管理员批准模式 改成已启用就行

活动预告 |【Part1】Microsoft Azure 在线技术公开课:数据基础知识

课程介绍 参加“Azure 在线技术公开课&#xff1a;数据基础知识”活动&#xff0c;了解有关云环境和数据服务中核心数据库概念的基础知识。通过本次免费的介绍性活动&#xff0c;你将提升在关系数据、非关系数据、大数据和分析方面的技能。 活动时间&#xff1a;01 月 07 日…

SQL-leetcode-183. 从不订购的客户

183. 从不订购的客户 Customers 表&#xff1a; -------------------- | Column Name | Type | -------------------- | id | int | | name | varchar | -------------------- 在 SQL 中&#xff0c;id 是该表的主键。 该表的每一行都表示客户的 ID 和名称。 Orders 表&#…

HTML5滑块(Slider)

HTML5 的滑块&#xff08;Slider&#xff09;控件允许用户通过拖动滑块来选择数值。以下是如何实现一个简单的滑块组件的详细说明。 HTML5 滑块组件 1. 基本结构 使用 <input type"range"> 元素可以创建一个滑块。下面是基本实现的代码示例&#xff1a; <…

报错:websocket注入为null,已解决!

错误截图 原因分析&#xff1a; WebSocket 在 Spring 框架中的注入问题是由其生命周期与 Spring 容器的作用域不一致引起的。spring管理的都是单例&#xff08;singleton&#xff09;&#xff0c;和 websocket &#xff08;多对象&#xff09;相冲突。如果你的WebSocket 处理类…

ClickHouse副本搭建

一. 副本概述 副本的目的主要是保障数据的高可用性&#xff0c;ClickHouse中的副本没有主从之分。所有的副本都是平等的。 副本写入流程&#xff1a; 二. 副本搭建 1. 实验环境 hadoop1(192.168.47.128) hadoop2(192.168.47.129)2. 修改配置文件 修改两台主机/etc/click…

ChatBI来啦!NBAI 正式上线 NL2SQL 功能

NebulaAI 现已正式上线 NL2SQL 功能&#xff0c;免费开放使用&#xff01; 什么是 NL2SQL&#xff1f;NL2SQL 即通过自然语言交互&#xff0c;用户可以轻松查询、分析和管理数据库中的数据&#xff08;ChatBI&#xff09;&#xff0c;从此摆脱传统复杂的数据库操作。 欢迎免费…

科技云报到:洞见2025年科技潮流,技术大融合开启“智算时代”

科技云报到原创。 随着2024年逐渐接近尾声&#xff0c;人们不禁开始展望即将到来的2025年。这一年&#xff0c;被众多科技界人士视为开启新纪元的关键节点。站在新的起点上&#xff0c;我们将亲眼目睹未来科技如何改变我们的世界。从人工智能到量子计算&#xff0c;从基因编辑…

【数据仓库】spark大数据处理框架

文章目录 概述架构spark 架构角色下载安装启动pyspark启动spark-sehll启动spark-sqlspark-submit经验 概述 Spark是一个性能优异的集群计算框架&#xff0c;广泛应用于大数据领域。类似Hadoop&#xff0c;但对Hadoop做了优化&#xff0c;计算任务的中间结果可以存储在内存中&a…

标准库以及HAL库——按键控制LED灯代码

按键控制LED本质还是控制GPIO,和点亮一个LED灯没什么区别 点亮一个LED灯&#xff1a;是直接控制输出引脚&#xff0c;GPIO初始化推挽输出即可 按键控制LED&#xff1a;是按键输入信号从而控制输出引脚&#xff0c;GPIO初始化推挽输出一个引脚以外还得加一个GPIO上拉输入 但是…

Rabbitmq追问2

分析rabbitmq 默认使用姿势是什么 direct fanout还是什么 public void convertAndSend(String exchange, String routingKey, Object object, CorrelationData correlationData) throws AmqpException { this.send(exchange, routingKey, this.convertMessageIfNecessary(obje…

vue+js+Java在分页的el-table里实现上移、下移;置顶

这里写目录标题 一、上移、下移二、置顶 一、上移、下移 实现&#xff1a;上移到第一行后不能再上移&#xff0c;下移到最后一行不能下移&#xff0c;以及分页后能上移到前一页&#xff0c;下移能移到后一页&#xff1b;&#xff08;新增sort排序字段&#xff09; <el-tabl…

计算机因进程结束导致白屏

问题场景&#xff1a; 计算机卡顿利用&#xff08;右击计算机桌面底部任务栏->打开任务管理器->结束任务->或进程被意外结束导致白屏&#xff09; 问题描述 白屏 原因分析&#xff1a; 在结束进程时&#xff0c;导致 文件资源管理器 进程崩溃。 解决方案&#xf…