Java实现日志全链路追踪.精确到一次请求的全部流程

news2024/11/26 22:20:12

广大程序员在排除线上问题时,会经常遇见各种BUG.处理这些BUG的时候日志就格外的重要.只有完善的日志才能快速有效的定位问题.为了提高BUG处理效率.我决定在日志上面优化.实现每次请求有统一的id.通过id能获取当前接口的全链路流程走向. 

实现效果如下: 一次查询即可找到所有关键信息.不再被多线程日志进行困扰了.

1:日志打印框架log4j ->  logback

logback是springboot默认自带的日志框架。不仅速度更快,而且内存占用也更小. (如果之前没用过log4j的建议先去学习下怎么使用).

打印日志的配置文件如下:  logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds">
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<jmxConfigurator/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<Target>System.out</Target>
<encoder>
<charset>UTF-8</charset>
<pattern>%d - [%t] %-5p %c:%L %X - %m%n</pattern>
</encoder>
</appender>
<appender name="DAILY_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<Append>true</Append>
<!--  日志输出路径 -->
<File>/opt/logs/logOut.log</File>
<encoder>
<charset>UTF-8</charset>
<pattern>%d - [%t] %-5p %c:%L %X - %m%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>/opt/logs/logOut.log.%d{yyyy-MM-dd}</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread][%X{traceId}] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>/opt/logs/logOut-error.log</File>
<Append>true</Append>
<encoder>
<charset>UTF-8</charset>
<pattern>%d - [%t] %-5p %c:%L %X - %m%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>/opt/logs/logOut-error.log.%d{yyyy-MM-dd}</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
</appender>



<logger name="org.springframework" level="INFO"/>
<root level="INFO">
<appender-ref ref="DAILY_FILE"/>
<appender-ref ref="ROLLING_FILE"/>
</root>
</configuration>

重点是这行代码

<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread][%X{traceId}] %-5level %logger{50} - %msg%n</pattern>

此时的配置文件打印只能出现 年月日-线程名这些关键信息.无法获得每次请求的唯一id.所以我们需要创建一个拦截器.将每次请求生成一个id.通过id把本次请求覆盖到每个流程中.

2.1: 编写 http请求 拦截器

public class TraceWebInterceptor extends HandlerInterceptorAdapter {
 
    private static final Logger LOGGER = LoggerFactory.getLogger(TraceWebInterceptor.class);
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        request.setAttribute("startTime", System.currentTimeMillis());
        //traceOrigin、traceCaller、traceId
        String traceOrigin = request.getHeader(TraceConstants.LOG_TRACE_ORIGIN);
        String traceCaller = request.getHeader(TraceConstants.LOG_TRACE_CALLER);
        String traceId = request.getHeader(TraceConstants.LOG_TRACE_ID);
 
        //如果不存在traceId需要生成
        if (StringUtils.isBlank(traceId)) {
            boolean generate = TraceUtil.loadTraceInfo();
            if(generate) {
                LOGGER.debug("[生成追踪信息]" + TraceUtil.getTraceInfoString());
            }
        }else {
            //设置MDC
            MDC.put(TraceConstants.LOG_TRACE_ORIGIN, traceOrigin);
            MDC.put(TraceConstants.LOG_TRACE_CALLER, traceCaller);
            MDC.put(TraceConstants.LOG_TRACE_ID, traceId);
        }
 
        //IP
        String traceIp = IpUtil.getIp(request);
        MDC.put(TraceConstants.LOG_TRACE_IP, traceIp);
 
        //响应返回
        response.setHeader(TraceConstants.LOG_TRACE_ID, TraceUtil.getTraceId());
 
        return super.preHandle(request, response, handler);
    }
 
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws IOException {
        if (LOGGER.isInfoEnabled()) {
            long upmsStartTime = (long) request.getAttribute("startTime");
            long upmsEndTime = System.currentTimeMillis();
            long upmsIntervalTime = upmsEndTime - upmsStartTime;
            LOGGER.info("{} {}接口耗时{}毫秒", request.getRequestURL(), request.getMethod(), upmsIntervalTime);
        }
        MDC.clear();
    }

2.2 编写Config类, 将拦截器TraceWebInterceptor添加到容器

@Configuration
@ConditionalOnClass({HandlerInterceptorAdapter.class, MDC.class, HttpServletRequest.class})
public class TraceWebAutoConfiguration implements WebMvcConfigurer {
 
    private static List<String> EXCLUDE_PATHS = new ArrayList<>();
 
    @Value("${" + TraceConstants.CONFIG_TRACE_EXCLUDE_PATHS + ":}")
    private String excludePaths;
 
    @Bean
    public TraceWebInterceptor traceWebInterceptor() {
        return new TraceWebInterceptor();
    }
 
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        EXCLUDE_PATHS.add("/error");
        EXCLUDE_PATHS.add("/actuator/**");
 
        if (StringUtils.isNotBlank(excludePaths)) {
            if (excludePaths.contains(",")) {
                String[] split = excludePaths.split(",");
                EXCLUDE_PATHS.addAll(Arrays.asList(split));
            } else {
                EXCLUDE_PATHS.add(excludePaths);
            }
        }
 
        //该方式不能过全部过滤掉
        registry.addInterceptor(traceWebInterceptor()).order(-100).excludePathPatterns(EXCLUDE_PATHS);
    }
}

2.3 编写工具类

import javax.servlet.http.HttpServletRequest;


public class IpUtil {
    private static final String UNKNOWN = "unknown";

    public static String getIp(HttpServletRequest request) {
        if (request == null) {
            return UNKNOWN;
        }
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Forwarded-For");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }
}

public class TraceConstants {
    public static final String LOG_TRACE_ORIGIN = "traceOrigin";
    public static final String LOG_TRACE_CALLER = "traceCaller";
    public static final String LOG_TRACE_IP = "traceIp";
    public static final String LOG_TRACE_ID = "traceId";

    public static final String CONFIG_TRACE_EXCLUDE_PATHS = "trace.exclude.paths";

    public TraceConstants() {
    }
}

import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;

import java.util.UUID;

public class TraceUtil {
    private static boolean simbaHttpClientInterceptorFlag = true;
    private static boolean sdkInterceptorFlag = false;
    private static String applicationName;

    public TraceUtil() {
    }

    public static void setApplicationName(String applicationName) {
        TraceUtil.applicationName = applicationName;
    }

    public static String getApplicationName() {
        return applicationName;
    }

    public static boolean getSimbaHttpClientInterceptorFlag() {
        return simbaHttpClientInterceptorFlag;
    }

    public static void setSimbaHttpClientInterceptorFlag(boolean simbaHttpClientInterceptorFlag) {
        TraceUtil.simbaHttpClientInterceptorFlag = simbaHttpClientInterceptorFlag;
    }

    public static boolean getSdkInterceptorFlag() {
        return sdkInterceptorFlag;
    }

    public static void setSdkInterceptorFlag(boolean sdkInterceptorFlag) {
        TraceUtil.sdkInterceptorFlag = sdkInterceptorFlag;
    }

    public static void setTraceCaller(String traceCaller) {
        MDC.put("traceCaller", traceCaller);
    }

    public static String getTraceCaller() {
        return MDC.get("traceCaller");
    }

    public static void setTraceOrigin(String traceOrigin) {
        MDC.put("traceOrigin", traceOrigin);
    }

    public static String getTraceOrigin() {
        return MDC.get("traceOrigin");
    }

    public static void setTraceId(String traceId) {
        MDC.put("traceId", traceId);
    }

    public static void removeTraceId() {
        MDC.remove("traceId");
    }

    public static void clearMdc() {
        MDC.clear();
    }

    public static String getTraceId() {
        return MDC.get("traceId");
    }

    public static String genTraceId() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    public static String getTraceIp() {
        return MDC.get("traceIp");
    }

    public static void setTraceIp(String traceIp) {
        MDC.put("traceIp", traceIp);
    }

    public static boolean loadTraceInfo() {
        boolean generate = false;
        String traceId = getTraceId();
        if (StringUtils.isBlank(traceId)) {
            traceId = genTraceId();
            generate = true;
        }

        setTraceId(traceId);
        return generate;
    }

    public static String getTraceInfoString() {
        return "TraceId:" + getTraceId() + ". traceCaller:" + getTraceCaller() + ". traceOrigin:" + getTraceOrigin();
    }
}

import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Configuration
@ConditionalOnClass({HandlerInterceptorAdapter.class, MDC.class, HttpServletRequest.class})
public class TraceWebAutoConfiguration implements WebMvcConfigurer {

    private static List<String> EXCLUDE_PATHS = new ArrayList<>();

    @Value("${" + TraceConstants.CONFIG_TRACE_EXCLUDE_PATHS + ":}")
    private String excludePaths;

    @Bean
    public TraceWebInterceptor traceWebInterceptor() {
        return new TraceWebInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        EXCLUDE_PATHS.add("/error");
        EXCLUDE_PATHS.add("/actuator/**");

        if (StringUtils.isNotBlank(excludePaths)) {
            if (excludePaths.contains(",")) {
                String[] split = excludePaths.split(",");
                EXCLUDE_PATHS.addAll(Arrays.asList(split));
            } else {
                EXCLUDE_PATHS.add(excludePaths);
            }
        }

        //该方式不能过全部过滤掉
        registry.addInterceptor(traceWebInterceptor()).order(-100).excludePathPatterns(EXCLUDE_PATHS);
    }
}

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class TraceWebInterceptor extends HandlerInterceptorAdapter {

        private static final Logger LOGGER = LoggerFactory.getLogger(TraceWebInterceptor.class);

        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
                request.setAttribute("startTime", System.currentTimeMillis());
                //traceOrigin、traceCaller、traceId
                String traceOrigin = request.getHeader(TraceConstants.LOG_TRACE_ORIGIN);
                String traceCaller = request.getHeader(TraceConstants.LOG_TRACE_CALLER);
                String traceId = request.getHeader(TraceConstants.LOG_TRACE_ID);

                //如果不存在traceId需要生成
                if (StringUtils.isBlank(traceId)) {
                        boolean generate = TraceUtil.loadTraceInfo();
                        if (generate) {
                                LOGGER.debug("[生成追踪信息]" + TraceUtil.getTraceInfoString());
                        }
                } else {
                        //设置MDC
                        MDC.put(TraceConstants.LOG_TRACE_ORIGIN, traceOrigin);
                        MDC.put(TraceConstants.LOG_TRACE_CALLER, traceCaller);
                        MDC.put(TraceConstants.LOG_TRACE_ID, traceId);
                }

                //IP
                String traceIp = IpUtil.getIp(request);
                MDC.put(TraceConstants.LOG_TRACE_IP, traceIp);

                //响应返回
                response.setHeader(TraceConstants.LOG_TRACE_ID, TraceUtil.getTraceId());

                return super.preHandle(request, response, handler);
        }

        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws IOException {
                if (LOGGER.isInfoEnabled()) {
                        long upmsStartTime = (long) request.getAttribute("startTime");
                        long upmsEndTime = System.currentTimeMillis();
                        long upmsIntervalTime = upmsEndTime - upmsStartTime;
                        LOGGER.info("{} {}接口耗时{}毫秒", request.getRequestURL(), request.getMethod(), upmsIntervalTime);
                }
                MDC.clear();
        }
}

import org.slf4j.MDC;

import java.util.Map;
import java.util.concurrent.*;

public class WrapUtil {

    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);
            }
            TraceUtil.loadTraceInfo();
            try {
                return callable.call();
            } finally {
                MDC.clear();
            }
        };
    }

    public static <T> Callable<T> wrap(final Callable<T> callable) {
        return wrap(callable, MDC.getCopyOfContextMap());
    }

    public static Runnable wrap(final Runnable runnable, final Map<String, String> context) {
        return () -> {
            if (context == null) {
                MDC.clear();
            } else {
                MDC.setContextMap(context);
            }
            TraceUtil.loadTraceInfo();
            try {
                runnable.run();
            } finally {
                MDC.clear();
            }
        };
    }

    public static Runnable wrap(final Runnable runnable) {
        return wrap(runnable, MDC.getCopyOfContextMap());
    }

    public static ThreadPoolExecutor newThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                                           BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
                                                           RejectedExecutionHandler handler) {
        return new ThreadPoolExecutorMdcWrapper(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
    }

    public static ThreadPoolExecutor newThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                                           BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        return new ThreadPoolExecutorMdcWrapper(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
    }

    public static ThreadPoolExecutor newThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                                           BlockingQueue<Runnable> workQueue) {
        return new ThreadPoolExecutorMdcWrapper(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    public static ThreadPoolExecutor newThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                                           BlockingQueue<Runnable> workQueue,
                                                           RejectedExecutionHandler handler) {
        return new ThreadPoolExecutorMdcWrapper(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
    }


    public static ForkJoinPool newForkJoinPool() {
        return new ForkJoinPoolMdcWrapper();
    }

    public static class ThreadPoolExecutorMdcWrapper extends ThreadPoolExecutor {
        public ThreadPoolExecutorMdcWrapper(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                            BlockingQueue<Runnable> workQueue) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
        }

        public ThreadPoolExecutorMdcWrapper(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                            BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
        }

        public ThreadPoolExecutorMdcWrapper(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                            BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
        }

        public ThreadPoolExecutorMdcWrapper(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                            BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
                                            RejectedExecutionHandler handler) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
        }

        @Override
        public void execute(Runnable task) {
            super.execute(WrapUtil.wrap(task, MDC.getCopyOfContextMap()));
        }

        @Override
        public <T> Future<T> submit(Runnable task, T result) {
            return super.submit(WrapUtil.wrap(task, MDC.getCopyOfContextMap()), result);
        }

        @Override
        public <T> Future<T> submit(Callable<T> task) {
            return super.submit(WrapUtil.wrap(task, MDC.getCopyOfContextMap()));
        }

        @Override
        public Future<?> submit(Runnable task) {
            return super.submit(WrapUtil.wrap(task, MDC.getCopyOfContextMap()));
        }
    }

    public static class ForkJoinPoolMdcWrapper extends ForkJoinPool {
        public ForkJoinPoolMdcWrapper() {
            super();
        }

        public ForkJoinPoolMdcWrapper(int parallelism) {
            super(parallelism);
        }

        public ForkJoinPoolMdcWrapper(int parallelism, ForkJoinWorkerThreadFactory factory,
                                      Thread.UncaughtExceptionHandler handler, boolean asyncMode) {
            super(parallelism, factory, handler, asyncMode);
        }

        @Override
        public void execute(Runnable task) {
            super.execute(WrapUtil.wrap(task, MDC.getCopyOfContextMap()));
        }

        @Override
        public <T> ForkJoinTask<T> submit(Runnable task, T result) {
            return super.submit(WrapUtil.wrap(task, MDC.getCopyOfContextMap()), result);
        }

        @Override
        public <T> ForkJoinTask<T> submit(Callable<T> task) {
            return super.submit(WrapUtil.wrap(task, MDC.getCopyOfContextMap()));
        }
    }
}

把工具类加上后.此时运行项目. 如果报错就处理下依赖导包. 不报错就说明可以正常使用了. 然后发布代码.运行方法.去查看日志吧. 此时每次请求都已经生成唯一ID了.

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

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

相关文章

前端面试题13(API请求方法)

在前端JavaScript中&#xff0c;进行API请求主要可以通过几种方式来实现&#xff0c;最常见的是使用XMLHttpRequest&#xff08;较旧的方法&#xff09;、fetch&#xff08;现代浏览器推荐方法&#xff09;以及使用第三方库如axios或jQuery.ajax等。 1. XMLHttpRequest 这是最…

MPI hello world SSH 免密互联

目标&#xff1a; 我们想实现2台主机免密互联&#xff0c;将MPI Hello World跑起来 假设hostname是node01,node02,&#xff08;Linux shell窗口一般是UserNameHostName&#xff0c;node1和node2一定要和HostName一样&#xff09; hostname是/etc/hosts中的配置&#xff0c;如下…

工地/矿区/电力/工厂/环卫视频智能安全监控反光衣AI检测算法的原理及场景应用

一、引言 随着科技的快速发展&#xff0c;特别是在智能交通和安全生产领域&#xff0c;对于夜间或弱光环境下的人员识别和安全监控需求日益凸显。反光衣作为一种重要的安全装备&#xff0c;被广泛应用于道路施工、工地作业、夜间巡逻、安全生产等场景&#xff0c;旨在提高人员的…

【CUDA】 矩阵乘法 matMatMul

矩阵乘法 matMatMul 矩阵乘法是基本线性代数子程序&#xff08;BLAS&#xff09;的重要组成部分&#xff0c;而且线性代数中许多其他操作以此为基础。 图1是两个矩阵的乘法。 基础方法&#xff0c;正方形tile和长方形tile 基础方法 执行矩阵乘法的基础方法是使用单个线程执…

2021-06-15 protues(ISIS)脉冲发生器仿真仪表使用

缘由这个脉冲发生器怎么连线_编程语言-CSDN问答

STM32智能交通管理系统教程

目录 引言环境准备智能交通管理系统基础代码实现&#xff1a;实现智能交通管理系统 4.1 数据采集模块 4.2 数据处理与分析 4.3 控制系统实现 4.4 用户界面与数据可视化应用场景&#xff1a;交通管理与优化问题解决方案与优化收尾与总结 1. 引言 智能交通管理系统利用STM32嵌…

【对顶堆 优先队列】295. 数据流的中位数

本文涉及知识点 对顶堆 优先队列 LeetCode295. 数据流的中位数 中位数是有序整数列表中的中间值。如果列表的大小是偶数&#xff0c;则没有中间值&#xff0c;中位数是两个中间值的平均值。 例如 arr [2,3,4] 的中位数是 3 。 例如 arr [2,3] 的中位数是 (2 3) / 2 2.5 …

网络漏洞挖掘实测报告

关于作者&#xff1a;个人主页 网络漏洞挖掘实测报告 一、前言 网络漏洞挖掘是信息安全领域中至关重要的一环。通过挖掘和修复漏洞&#xff0c;可以有效地保护系统免受潜在的攻击和破坏。本报告旨在记录一次完整的网络漏洞挖掘实测过程&#xff0c;包括实施方法、过程、结果以…

免杀笔记 ----> ShellCode Loader !!!

学了那么久的前置知识&#xff0c;终于到了能上线的地方了&#xff01;&#xff01;&#xff01; 不过这里还没到免杀的部分&#xff0c;距离bypass一众的杀毒软件还有很长的路要走&#xff01;&#xff01; 目录 1.ShellCode 2.ShellCode Loader的概念 3.可读可写可…

Android实现获取本机手机号码

和上次获取设备序列号一样&#xff0c;仍然是通过无障碍服务实现&#xff0c;在之前的代码基础上做了更新。代码和demo如下&#xff1a; package com.zwxuf.lib.devicehelper;import android.accessibilityservice.AccessibilityService; import android.app.Activity; import…

Java中使用arima预测未来数据

看着已经存在的曲线图数据&#xff0c;想预估下后面曲线图的数据。 import java.util.Vector;public class AR {double[] stdoriginalData{};int p;ARMAMath armamathnew ARMAMath();/*** AR模型* param stdoriginalData* param p //p为MA模型阶数*/public AR(double [] stdori…

Dungeonborne延迟高?降低Dungeonborne延迟的方法分享

Dungeonborne是Mithril Interactive开发并发行的一款沉浸式第一人称 PvPvE 地下城探险游戏。Dungeonborne的魅力并不仅仅在于战斗和冒险。游戏中的剧情设计同样引人入胜&#xff0c;每个NPC都有自己独特的故事和背景&#xff0c;玩家在与他们交流的过程中&#xff0c;不仅能了解…

Tomcat(+Servlet)笔记+代码

Tomcat安装和配置 安装在不含中文的路径&#xff0c;路径不能太长 Apache 官网&#x1f447; Apache Tomcat - Welcome! 配置部分 点击下图红框处&#xff0c;找到Tomcat安装位置 添加项目的文件 配好的话&#xff0c;红框这里有个猫 代码部分 新建jsp文件&#xff0c;里…

【码银送书第二十二期】《Python数据分析从入门到精通(第2版)》

&#x1f490;大家好&#xff01;我是码银~&#xff0c;欢迎关注&#x1f490;&#xff1a; CSDN&#xff1a;码银 公众号&#xff1a;码银学编程 前言 &#x1f340;丛书说明&#xff1a;“软件开发视频大讲堂‘’丛书第1版于2008年8月出版&#xff0c;因其编写细腻、易学实用…

字符串函数5-9题(30 天 Pandas 挑战)

字符串函数 1. 相关知识点1.5 字符串的长度条件判断1.6 apply映射操作1.7 python大小写转换1.8 正则表达式匹配2.9 包含字符串查询 2. 题目2.5 无效的推文2.6 计算特殊奖金2.7 修复表中的名字2.8 查找拥有有效邮箱的用户2.9 患某种疾病的患者 1. 相关知识点 1.5 字符串的长度条…

Orangepi配合IIC驱动OLED屏幕

目录 一、OLED屏幕 二、Orangepi的IIC接口及OLED屏幕硬件接线 2.1 Orangepi的IIC接口&#xff1a; 2.2 Orangepi与OLED屏幕硬件接线&#xff1a; 三、wiringPi库示例代码 3.1 wiringPi库OLED屏幕示例代码&#xff1a; 3.2 OLED显示自己想要的字符&#xff1a; 一、OLED屏…

E2.【C语言】练习:static部分

#include <stdio.h> int sum(int a) {int c 0;static int b 3;c 1;b 2;return (a b c); } int main() {int i;int a 2;for (i 0; i < 5;i){printf("%d ", sum(a));} } 求执行结果 c是auto类变量(普通的局部变量)&#xff0c;自动产生&#xff0c…

第26篇 寻找最大数<一>

Q&#xff1a;如何设计一段汇编语言子程序并调用来寻找一组数中的最大数呢&#xff1f; A&#xff1a;基本原理&#xff1a;可以使用子程序LARGE实现找到列表中最大数的功能。主程序通过寄存器将列表的条目数和起始地址作为参数传递给子程序&#xff0c;子程序通过寄存器将最大…

qt 如果把像素点数据变成一个图片

1.概要 图像的本质是什么&#xff0c;就是一个个的像素点&#xff0c;对与显示器来说就是一个二维数组。无论多复杂的图片&#xff0c;对于显示器来说就是一个二维数组。 2.代码 #include "widget.h"#include <QApplication> #include <QImage> #incl…

Springboot学习之用EasyExcel4导入导出数据(基于MyBatisPlus)

一、POM依赖 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><m…