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,一经查实,立即删除!

相关文章

python标准库os的方法listdir_Python 标准库 os 中的方法 listdir() 返回包含指定路径中所有文件和文件夹名称的列表。_药理学答案_学小易找答案...

【单选题】下列( )是脂肪酸 (2.0分)【单选题】关于固醇类的叙述,错误的是( ) (2.0分)【单选题】细胞膜的主动转运( ) (2.0分)【单选题】脂肪的碱水解作用又称为( ) (2.0分)【名词解释】比活力【简答题】4、什么是米氏方程,米氏常数 Km 的意义是什么?试求酶反应速度达到最大反应…

JS遍历数组的12种方法

一、 for 普通版 for (let i 0; i < arr.lengthl; i) {// ... }优化版 // 使用临时变量&#xff0c;将长度缓存起来&#xff0c;避免重复获取数组长度&#xff0c;当数组较大时优化效果才会比较明显。 let len arr.length; for (let i 0; i < len; i) {// ... }for…

Log4j2突发重大漏洞

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

不改变原数组的一些方法

改变原数组 push / pop / shift / unshift / sort / reverse / splice 不改变原数组 concat / join --> split / toString / slice 一、 concat — 数组合并 var arr [1, 2, 3]; var arr1 [4, 5, 6]; console.log(arr.concat(arr1)); // [1, 2, 3, 4, 5, 6];二、 toStri…

python描述对象静态特性的数据为_对于需要几个单位共同负担的一张原始凭证上的支出,应根据其他单位负担部分为其提高( )。...

【单选题】字符串s是一个字符序列,以下表示s从右侧向左第三个字符的是: ‪‪‪‫‪‪‪‪‪‪‫‪‪‪‪‪‫‫‪‪‪‪‪‪‪‪‪‪‪‪‫‪‪‪‪‪‪【多选题】我国《婚姻法》规定夫妻人身关系的内容包括 ( )【填空题】白露横江【多选题】我国《婚姻法》规定的婚姻成立的实质…

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

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

arguments 类数组

一、类数组&#xff1a;长得像数组&#xff0c;可以拿它当数组用&#xff0c;但它不是数组 可以利用属性名模拟数组的特性可以动态的增长 length 的属性如果强行让类数组调用 push 方法&#xff0c;则会根据 length 属性值的位置进行属性的扩充 二、不能往类数组里面添加东西…

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

很忏愧&#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就是系统守护进程,守护系统级的服务.我的个人理解就是管理系统服务的工具,可以对系统服务做一些操作,如:启动、结束、重启等,这里我…

js 函数参数

函数有了参数才变得强大。 一、参数规则 形参比实参多&#xff0c;多的形参赋值undefined 实参比形参多&#xff0c;有多少形参就对应赋多少实参&#xff0c;其余的放到 arguments arguments[] 是一个类数组 – 实参列表 // 形式参数 -- 形参 -- 用来占位的 function fun(a,…

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 开源许可协…

函数的结束条件和返回值 — return

一、当做返回值 function sum(a, b) {return a b; }sum(1, 2); // 3二、作为函数的终止条件 函数遇到 return 就会停止 function sum(a, b) {console.log(a);return; // 如果 return 写在这里&#xff0c;后面的语句通通不会执行console.log(b); }sum(1, 2);输入数字&#x…

java面试题:当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?

java面试题&#xff1a;当一个对象被当作参数传递到一个方法后&#xff0c;此方法可改变这个对象的属性&#xff0c;并可返回变化后的结果&#xff0c;那么这里到底是值传递还是引用传递? 答&#xff1a;是值传递。Java编程语言只有值传递参数。 当一个对象实例作为一个参数…

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

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

函数的作用域以及预编译

一、函数的作用域 函数作用域有点像单面镜&#xff08;外面看不到里面&#xff0c;里面可以看到外面&#xff09;JS的特点&#xff1a;单线程、是 解释性语言 (翻译一行&#xff0c;执行一行) 二、预解析 JS预解析三部曲&#xff1a;语法解析 ⇒ 预编译 ⇒ 解释执行 JS 在执…

完整版PayPal支付(java后端教程)

首先引入 PayPal的sdk 这里我引入的是1.0.4版本的 <!-- 贝宝支付 SDK --><dependency><groupId>com.paypal.sdk</groupId><artifactId>checkout-sdk</artifactId><paypal-sdk.version>1.0.4</paypal-sdk.version></depe…

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

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

js 闭包

一、闭包的作用 实现公有变量 — 函数累加器可以做缓存&#xff08;存储结构&#xff09;可以实现封装&#xff0c;属性私有化模块化开发&#xff0c;防止污染全局变量 闭包实现 1 … 100 function add() {var count 0;function demo() {count;console.log(count);}retur…