log4j2 的使用【超详细图文】

log4j2 的使用

Apache Log4j2 是对Log4j 的升级版本,参考了logback 的一些优秀的设计,并且修复了一些问题,因此带来了一些重大的提升,主要有:

  • 异常处理,在logback中,Appender中的异常不会被应用感知到,但是在log4j2中,提供了一些异常处理机制。
  • 性能提升,log4j2 相较于log4j 和 logback 都具有明显的性能提升,有18倍性能提升,后面会有官方测试的数据。
  • 自动重载配置,参考了logback的设计,当然会提供自动刷新参数配置,最实用的就是我们在生产上可以动态的修改日志的级别而不需要重启应用。
  • 无垃圾机制,log4j2 在大部分情况下,都可以使用其设计的一套无垃圾机制【对象重用、内存缓冲】,避免频繁的日志收集导致的 jvm gc。

官网:https://logging.apache.org/log4j/2.x/


一. Log4j2 入门

目前市面上最主流的日志门面就是SLF4J,虽然Log4j2 也是日志门面,因为它的日志实现功能非常强大,性能优越。所以大家一般还是将 Log4j2 看作是日志的实现,Slf4j + Log4j2 应该是未来的大势所趋

1.添加依赖

    <dependencies><!-- log4j2 日志门面 --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.11.1</version></dependency><!-- log4j2 日志实面 --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.11.1</version></dependency><!-- junit 单元测试 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency></dependencies>

2.编写代码

package com.log;import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.Test;public class Log4j2Test {// 定义日志记录器对象public static final Logger LOGGER = LogManager.getLogger(Log4j2Test.class);// 快速入门@Testpublic void testQuick() throws Exception {// 日志消息输出LOGGER.fatal("fatal");LOGGER.error("error");LOGGER.warn("warn");LOGGER.info("info");LOGGER.debug("debug");LOGGER.trace("trace");}
}

3.运行结果截图

img

上述报错是因为没有找到日志配置文件,需要添加 log4j2.xml 配置文件到 resource 目录下【classpath】下。log4j2 默认加载classpath 下的 log4j2.xml 文件中的配置

<?xml version="1.0" encoding="UTF-8" ?>
<configuration status="warn" monitorInterval="5"><properties><property name="LOG_HOME">E:/logs</property></properties><Appenders><Console name="Console" target="SYSTEM_OUT"><PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] [%-5level] %c{36}:%L --- %m%n" /></Console><File name="file" fileName="${LOG_HOME}/myfile.log"><PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %m%n" /></File><RandomAccessFile name="accessFile" fileName="${LOG_HOME}/myAcclog.log"><PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %m%n" /></RandomAccessFile><RollingFile name="rollingFile" fileName="${LOG_HOME}/myrollog.log"filePattern="E:/logs/$${date:yyyy-MM-dd}/myrollog-%d{yyyy-MM-dd-HH-mm}-%i.log"><ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY" /><PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %msg%n" /><Policies><OnStartupTriggeringPolicy /><SizeBasedTriggeringPolicy size="10 MB" /><TimeBasedTriggeringPolicy /></Policies><DefaultRolloverStrategy max="30" /></RollingFile></Appenders><Loggers><Root level="trace"><AppenderRef ref="Console" /></Root></Loggers>
</configuration>

实际生产中,我们往往需要 slf4j + log4j2 进行日志管理;就需要导入slf4j 日志门面、log4j2 适配器;然后使用 slf4j 方法接口名称来输出日志

    <dependencies><!-- 使用slf4j 作为日志门面 --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.26</version></dependency><!-- 使用 log4j2 的适配器进行绑定 --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId><version>2.9.1</version></dependency><!-- log4j2 日志门面 --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.11.1</version></dependency><!-- log4j2 日志实面 --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.11.1</version></dependency><!-- junit 单元测试 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency></dependencies>

编写 slf4j + log4j2 代码

package com.log;import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class Slf4jTest {// 为了保证使用时,不需要每次都去创建logger 对象,我们声明静态常量public static final Logger LOGGER = LoggerFactory.getLogger(Slf4jTest.class);// 快速入门@Testpublic void testQuick(){// 日志输出LOGGER.error("error");LOGGER.warn("warning");LOGGER.info("info");    // 默认的日志级别信息LOGGER.debug("debug");LOGGER.trace("trace");  // 追踪信息// 使用占位符输出日志信息String name = "java_log";Integer age = 18;LOGGER.info("用户:{},{}", name, age);// 将系统的异常信息输出try {int i = 1 / 0;} catch (Exception e){// e.printStackTrace();LOGGER.error("出现异常:", e);}}
}

log4j2 vs slf4j + log4j2 日志输出对比:

img


二、Log4j2 配置

log4j2 默认加载classpath 下的 log4j2.xml 文件中的配置。下面通过log4j2.xml 配置文件进行测试

<?xml version="1.0" encoding="UTF-8" ?>
<!--status="warn" 日志框架本身的输出日志级别,可以修改为debugmonitorInterval="5" 自动加载配置文件的间隔时间,不低于 5秒;生产环境中修改配置文件,是热更新,无需重启应用-->
<configuration status="warn" monitorInterval="5"><!--集中配置属性进行管理使用时通过:${name}--><properties><property name="LOG_HOME">D:/logs</property></properties><!-- 日志处理 --><Appenders><!-- 控制台输出 appender,SYSTEM_OUT输出黑色,SYSTEM_ERR输出红色 --><Console name="Console" target="SYSTEM_OUT"><PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] [%-5level] %c{36}:%L --- %m%n" /></Console><!-- 日志文件输出 appender --><File name="file" fileName="${LOG_HOME}/myfile.log"><PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %m%n" /></File><!-- 使用随机读写流的日志文件输出 appender,性能提高 --><RandomAccessFile name="accessFile" fileName="${LOG_HOME}/myAcclog.log"><PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %m%n" /></RandomAccessFile><!-- 按照一定规则拆分的日志文件的appender -->  <!-- 拆分后的文件 --><!-- filePattern="${LOG_HOME}/$${date:yyyy-MM-dd}/myrollog-%d{yyyy-MM-dd-HH-mm}-%i.log"> --><RollingFile name="rollingFile" fileName="${LOG_HOME}/myrollog.log"filePattern="${LOG_HOME}/$${date:yyyy-MM-dd}/myrollog-%d{yyyy-MM-dd}-%i.log"><!-- 日志级别过滤器 --><ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY" /><!-- 日志消息格式 --><PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %msg%n" /><Policies><!-- 在系统启动时,出发拆分规则,生产一个新的日志文件 --><OnStartupTriggeringPolicy /><!-- 按照文件大小拆分,10MB --><SizeBasedTriggeringPolicy size="2MB" /><!-- 按照时间节点拆分,规则根据filePattern定义的 --><TimeBasedTriggeringPolicy /></Policies><!-- 在同一个目录下,文件的个限定为 30个,超过进行覆盖 --><DefaultRolloverStrategy max="10" /></RollingFile></Appenders><!-- logger 定义 --><Loggers><!-- 使用 rootLogger 配置 日志级别 level="trace" --><Root level="trace"><!-- 指定日志使用的处理器 --><!-- <AppenderRef ref="Console" />--><AppenderRef ref="file" /><AppenderRef ref="rollingFile" /><AppenderRef ref="accessFile" /></Root></Loggers>
</configuration>

编写代码:

package com.log;import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class Slf4jTest {// 为了保证使用时,不需要每次都去创建logger 对象,我们声明静态常量public static final Logger LOGGER = LoggerFactory.getLogger(Slf4jTest.class);// 快速入门@Testpublic void testQuick(){// 日志输出for (int i = 0; i < 1000000; i++) {LOGGER.error("error");LOGGER.warn("warning");LOGGER.info("info");    // 默认的日志级别信息LOGGER.debug("debug");LOGGER.trace("trace");  // 追踪信息}// 使用占位符输出日志信息/*String name = "java_log";Integer age = 18;LOGGER.info("用户:{},{}", name, age);// 将系统的异常信息输出try {int i = 1 / 0;} catch (Exception e){// e.printStackTrace();LOGGER.error("出现异常:", e);}*/}
}

运行结果截图:

img

img


三、Log4j2 异步日志

异步日志

log4j2 最大的特点就是异步日志,其性能的提升主要也是从异步日志中受益,我们来看看如何使用log4j2 的异步日志。

  • 同步日志

img

  • 异步日志

img

Log4j2 提供了两种实现日志的方式,一个是通过AsyncAppender【几乎没人用】,一个是通过AsyncLogger【主要是这个】,分别对应前面我们说的Appender 组件和Logger 组件。

官网详细介绍:http://logging.apache.org/log4j/2.x/performance.html

img

注意:配置异步日志需要添加依赖

        <!--异步日志依赖 --><dependency><groupId>com.lmax</groupId><artifactId>disruptor</artifactId><version>3.3.4</version></dependency>

1、AsyncAppender 方式【生产上几乎不使用,因为性能低下

<?xml version="1.0" encoding="UTF-8" ?>
<!--status="warn" 日志框架本身的输出日志级别,可以修改为debugmonitorInterval="5" 自动加载配置文件的间隔时间,不低于 5秒;生产环境中修改配置文件,是热更新,无需重启应用-->
<configuration status="warn" monitorInterval="5"><!--集中配置属性进行管理使用时通过:${name}--><properties><property name="LOG_HOME">D:/logs</property></properties><!-- 日志处理 --><Appenders><!-- 控制台输出 appender,SYSTEM_OUT输出黑色,SYSTEM_ERR输出红色 --><Console name="Console" target="SYSTEM_OUT"><PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] [%-5level] %c{36}:%L --- %m%n" /></Console><!-- 日志文件输出 appender --><File name="file" fileName="${LOG_HOME}/myfile.log"><!--<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %m%n" />--><PatternLayout pattern="%d %p %c{1.} [%t] %m%n" /></File><Async name="Async"><AppenderRef ref="file" /></Async></Appenders><!-- logger 定义 --><Loggers><!-- 使用 rootLogger 配置 日志级别 level="trace" --><Root level="trace"><!-- 指定日志使用的处理器 --><AppenderRef ref="Console" /><!-- 使用异步 appender --><AppenderRef ref="Async" /></Root></Loggers>
</configuration>

2、编写代码

package com.log;import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class Slf4jTest {// 为了保证使用时,不需要每次都去创建logger 对象,我们声明静态常量public static final Logger LOGGER = LoggerFactory.getLogger(Slf4jTest.class);// 快速入门@Testpublic void testQuick(){// 日志输出LOGGER.error("error");LOGGER.warn("warning");LOGGER.info("info");    // 默认的日志级别信息LOGGER.debug("debug");LOGGER.trace("trace");  // 追踪信息}
}

3、运行结果截图,下面就是异步日志输出

img


2、AsyncLogger 方式【生产上用得多,因为性能高

AsyncLogger 才是log4j2 的重头戏,也是官方推荐的异步方式。它可以调用Logger.log 返回的更快。你可以有两种选择:全局异步和混合异步。

  • 全局异步就是,所有日志都异步的记录,在配置文件上不用做任何改动,只需要添加一个 log4j2.component.properties 配置到 resources;
Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector

img

则此时,向控制台、文件都是异步方式日志输出

img


  • 混合异步就是,你可以在应用中同时使用同步日志和异步日志,这使得日志的配置方式更加灵活,按如下配置主要是添加截图部分即可:
<?xml version="1.0" encoding="UTF-8" ?>
<!--status="warn" 日志框架本身的输出日志级别,可以修改为debugmonitorInterval="5" 自动加载配置文件的间隔时间,不低于 5秒;生产环境中修改配置文件,是热更新,无需重启应用-->
<configuration status="debug" monitorInterval="5"><!--集中配置属性进行管理使用时通过:${name}--><properties><property name="LOG_HOME">D:/logs</property></properties><!-- 日志处理 --><Appenders><!-- 控制台输出 appender,SYSTEM_OUT输出黑色,SYSTEM_ERR输出红色 --><Console name="Console" target="SYSTEM_OUT"><PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] [%-5level] %c{36}:%L --- %m%n" /></Console><!-- 日志文件输出 appender --><File name="file" fileName="${LOG_HOME}/myfile.log"><!--<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %m%n" />--><PatternLayout pattern="%d %p %c{1.} [%t] %m%n" /></File><Async name="Async"><AppenderRef ref="file" /></Async></Appenders><!-- logger 定义 --><Loggers><!-- 自定义 logger 对象includeLocation="false" 关闭日志记录的行号信息,开启的话会严重影响异步输出的性能additivity="false" 不再继承 rootlogger对象--><AsyncLogger name="com.log" level="trace" includeLocation="false" additivity="false"><AppenderRef ref="Console" /></AsyncLogger><!-- 使用 rootLogger 配置 日志级别 level="trace" --><Root level="trace"><!-- 指定日志使用的处理器 --><AppenderRef ref="Console" /><!-- 使用异步 appender --><AppenderRef ref="Async" /></Root></Loggers>
</configuration>

img

同时,AsyncLogger 混合异动日志输出需要将log4j2.component.properties 内容进行注释【因为这个是配置AsyncLogger全局异步日志输出】

img

如下配置:com.log 日志是异步的, root 日志是同步的。

使用异步日志需要注意的问题

  1. 如果使用异步日志,AsyncAppender、AsyncLogger 和全局日志,不要同时出现。性能会和AsyncAppender 一致,降至最低。
  2. 设置 includeLocation=false,打印位置信息会急剧降低异步日志的性能,比同步日志还要慢。

四、Log4j2 的性能

Log4j2 最牛的地方在于异步输出日志时的性能表现,Log4j2 在多线程的环境下吞吐量与 Log4j 和 Logback 的比较如下图。下图比较中 Log4j2 有三种模式:

  1. 全局使用异步模式;
  2. 部分Logger采用异步模式;
  3. 异步Appenderf。

可以看出在前两种模式下,Log4j2 的性能较之 Log4j 和Logback有很大的优势。

img

无垃圾记录

垃圾收集暂停是延迟峰值的常见原因,并且对于许多系统而言,花费大量精力来控制这些暂停。

许多日志库(包括以前版本的Log4j)在稳态日志记录期间分配临时对象,如日志事件对象,字符串,字符数组,字节数组等。这会对垃圾收集器造成压力并增加 GC 暂停发生的概率。

从版本2.6 开始,默认情况下 Log4j 以“无垃圾” 模式运行,其中重用对象和缓冲区,并且尽可能不分配临时对象。还有一个“低垃圾”模式,它不是完全无垃圾,但不使用ThreadLocal 字段。

Log4j 2.6 中的无垃圾日志记录部分通过重用ThreadLocal 字段中的对象来实现,部分通过在将文件转换为字节时重用缓冲区来实现。

使用Log4j 2.5:内存分配速度809 MB / 秒,141个无效集合。

img

Log4j 2.6没有分配临时对象:0(零)垃圾回收。

img

有两个单独的系统属性可用于手动控制Log4j 用于避免创建临时对象的机制:

  • log4j2.enableThreadlocals -如果"true"(非Web应用程序的默认值)对象存储在ThreadLocal 字段中并重新使用,否则将为每个日志事件创建新对象。
  • log4j2.enableDirectEncoders -如果将"true" (默认)日志事件转为文本,则将文本转换为字节而不创建临时对象。注意:由于共享缓冲区上的同步,在此模式下多线程应用程序的同步日志记录性能可能更差。

真诚的建议:如果您的应用程序是多线程的并且日志记录性能很重要,请考虑使用异步记录器。


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

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

相关文章

Log4j2突发重大漏洞

长话短说吧。 相信大家已经被 Log4j2 的重大漏洞刷屏了&#xff0c;估计有不少小伙伴此前为了修 bug 已经累趴下了。很不幸&#xff0c;我的小老弟小二的 Spring Boot 项目中恰好用的就是 Log4j2&#xff0c;版本特喵的还是 2.14.1&#xff0c;在这次漏洞波及的版本范围之内。…

PageHelper分页插件源码及原理剖析

摘要: com.github.pagehelper.PageHelper是一款好用的开源免费的Mybatis第三方物理分页插件。 PageHelper是一款好用的开源免费的Mybatis第三方物理分页插件&#xff0c;其实我并不想加上好用两个字&#xff0c;但是为了表扬插件作者开源免费的崇高精神&#xff0c;我毫不犹豫…

净网大师最好用旧版本_云顶之弈手把手教你吃分系列:决斗大师

很忏愧&#xff0c;这个阵容并非我原创&#xff0c;也是我偷师而来&#xff0c;不过最近一直在用&#xff0c;效果也不错&#xff0c;所以主要会讲讲心得&#xff0c;而不是原先的基础。先看阵容构成&#xff1a;亚索(天选决斗大师)、剑姬、武器、风女、卡莉斯塔/赵信、慎、永恩…

PageHelper 关闭COUNT(0)查询 以及PageHelper 的分页原理分析

pagehelper 关闭count(0)查询 以及pagehelper的分页原理分析 情景再现&#xff1a;在给移动端提供分页查询数据接口时&#xff0c;知道他们不需要总条数。但是使用pagehelper 分页查询打印的sql总是会查询两次&#xff0c;先统计条数&#xff0c;在进行列表查询。对于有点强迫…

local service system账户_systemd.service学习和使用总结

公众号&#xff1a;暮北林 Q Q 群 : 一起学前端Systemd Service 学习和使用总结什么是Systemd servicesystem就是系统,d的意思是daemon,systemd就是系统守护进程,守护系统级的服务.我的个人理解就是管理系统服务的工具,可以对系统服务做一些操作,如:启动、结束、重启等,这里我…

MySQL中OR和AND的区别是什么____MySQL中or与in

MySQL中OR和AND的区别是什么 区别如下&#xff1a; 1、or就是’或’得意思&#xff0c;只要其中一个条件成立就可以了&#xff1b; 2、and就是’与’得意思&#xff0c;并列&#xff0c;两个条件要都成立。 简明的说&#xff1a;and必须满足所有条件&#xff1b;or满足一个…

stm32 lwip 如何发送不出_mbedtls | 移植mbedtls库到STM32裸机的两种方法

一、mbedtls 开源库1. mbedtls是什么Mbed TLS是一个开源、可移植、易于使用、代码可读性高的SSL库。可实现加密原语&#xff0c;X.509证书操作以及SSL / TLS和 DTLS 协议&#xff0c;它的代码占用空间小&#xff0c;非常适合用于嵌入式系统。mbedtls遵循 Apache 2.0 开源许可协…

keras训练完以后怎么预测_农村小孩只有户口,没有承包地,以后怎么养老?看完我安心了...

阅读本文前&#xff0c;请您先点击上面的蓝色字体“三农荟”&#xff0c;再点击“关注”&#xff0c;这样您就可以继续免费收到最新情感文章了。每天都有分享。完全是免费订阅&#xff0c;请放心关注。 农村小孩&#xff0c;只有户口&#xff0c;没有属于自己的承包地&#xff…

mac玩rust用什么画质_Mac上的活动监视器到底有什么用?你会用么?

您希望当Mac卡住或沙滩球不断旋转时&#xff0c;Mac中有一个任务管理器。它允许您强制退出已冻结的网站或应用程序。Windows用户熟悉任务管理器&#xff0c;并且擅长使用它来管理PC任务以优化PC性能。因此&#xff0c;您想知道Mac上是否有任务管理器&#xff1f;是的&#xff0…

java实现 支付宝支付

文章目录支付宝开放平台官网创建demo实例分析效果图实例代码AlipayConfigPaymentControllerOrderService OrderServiceImplapplicationContext-alipay.xml支付宝开放平台官网 用自己手机支付宝扫码登录 根据页面提示填写自己真实信息 进去之后 东西主要用的就在这里 sdk 在 …

Java接入支付宝支付教程

Java接入支付宝支付教程 一、创建应用 1.登录支付宝开放平台 支付宝开放平台网址&#xff1a;https://open.alipay.com/platform/developerIndex.htm 2.创建一个应用 ? 图1 二 、设置应用密钥 1.下载安装支付宝开放平台助手 软件下载地址&#xff1a;https://gw.alipay…

虚拟同步发电机_测量虚拟同步发电机惯量与阻尼系数的新方法

华北电力大学分布式储能与微网河北省重点实验室的研究人员颜湘武、王俣珂、贾焦心、王德胜、张波&#xff0c;在2019年第7期《电工技术学报》上撰文(论文标题为“基于非线性最小二乘曲线拟合的虚拟同步发电机惯量与阻尼系数测量方法”)指出&#xff0c;虚拟同步发电机(VSG)技术…

SpringBoot整合阿里云OSS上传文件

一、需求分析 文件上传是一个非常常见的功能&#xff0c;就是通过IO流将文件写到另外一个地方&#xff0c;这个地方可以是项目下的某个文件夹里&#xff0c;或者是本地电脑某个盘下面&#xff0c;还可以是云服务OSS里面&#xff0c;这里就是我要讲到的OSS&#xff0c;我写的是…

js 原型以及原型链

原型编程的基本规则&#xff1a; 所有的数据都是对象要得到一个对象&#xff0c;不是通过实例化类&#xff0c;而是找到一个对象作为原型并克隆它对象会记住它的原型如果对象无法相应某个请求&#xff0c;它会把这个请求委托给它自己的原型 直接上图 一、继续说说构造函数 …

SpringBoot整合阿里云OSS文件上传、下载、查看、删除

SpringBoot整合阿里云OSS文件上传、下载、查看、删除 该项目源码地址&#xff1a;https://github.com/ggb2312/springboot-integration-examples &#xff08;其中包含SpringBoot和其他常用技术的整合&#xff0c;配套源码以及笔记。基于最新的 SpringBoot2.1&#xff0c;欢迎各…

SpringBoot整合oss实现文件的上传,查看,删除,下载

springboot整合oss实现文件的上传,查看,删除,下载 1.什么是对象存储 OSS? 答&#xff1a;阿里云对象存储服务&#xff08;Object Storage Service&#xff0c;简称 OSS&#xff09;&#xff0c;是阿里云提供的海量、安全、低成本、高可靠的云存储服务。其数据设计持久性不低…

minio实现文件上传下载和删除功能

前言 之前用到文件上传功能&#xff0c;在这里做个学习记录。使用minio实现&#xff0c;后面会记录使用fastdfs和阿里云的oss实现文件上传以及他们的比较&#xff08;oss根据流量收费&#xff09;。minio的中文文档&#xff1a;https://docs.min.io/cn/ minio安装 首先查询d…

Spring Boot配置MinIO(实现文件上传、下载、删除)

1 MinIO MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口&#xff0c;非常适合于存储大容量非结构化的数据&#xff0c;例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等&#xff0c;而一个对象文件可以是任意大小&#xff…

Stream中toMap引发NullPointerException____Stream的执行流程

Stream中toMap引发NullPointerException 1、引发NullPointerException的代码如下&#xff1a; List<SelfSettlementCardInfoDto> selfSettlementCardInfoDtos selfCardAdapterManager.listSelfSettlementCardInfoDtoByCardIds(queryDto.getPartnerId(), cardIds, false…

Map集合使用get方法返回null抛出空指针异常问题

Map集合使用get方法空指针异常问题 前言 1.Map里面只能存放对象&#xff0c;不能存放基本类型&#xff0c;例如int&#xff0c;需要使用Integer 2.Map集合取出时&#xff0c;如果变量声明了类型&#xff0c;会先进行拆箱&#xff0c;再进行转换。 空指针问题 如图&#xff…