(一)Apache log4net™ 手册 - 介绍

news/2023/11/28 17:04:49

0、相关概念

Log4j

几乎每个大型应用程序都包含自己的日志记录或跟踪 API。根据这一规则,E.U. SEMPER 🌹项目决定编写自己的跟踪 API。那是在 1996 年初。经过无数次的增强、几个化身和大量的工作,API 已经发展成为 log4j —— 一个流行的 Java 日志包。该软件包是在 Apache 软件许可证下发布的,这是一个由开源 🌹倡议组织认证的成熟的开源许可证。最新的 log4j 版本,包括完整的源代码、类文件和文档,可以在 https://logging.apache.org/log4j/2.x/index.html 🌹上找到。

在代码中插入日志语句是一种低技术含量的调试方法。这也可能是唯一的方法,因为调试器并不总是可用或适用的。这通常是多线程应用程序和分布式应用程序所要面临的情况。

经验表明,日志记录是开发周期的一个重要组成部分。它有几个优点。它提供了关于应用程序运行的精确上下文。一旦插入到代码中,日志输出的生成就不需要人工干预。此外,日志输出可以保存在持久介质中,以供以后研究。除了在开发周期中使用之外,一个功能足够丰富的日志包还可以被视为一个审计工具。

正如 Brian W. Kernighan 和 Rob Pike 在他们真正优秀的书《The Practice of Programming》中所说的那样:

作为个人选择,除了获取堆栈跟踪或一两个变量的值之外,我们倾向于不使用调试器。一个原因是它很容易迷失在复杂的数据结构和控制流的细节中;我们发现,与努力思考并在关键位置添加输出语句和自检代码相比,逐步执行程序的效率更低。点击语句比扫描精心放置的显示的输出要花更长的时间。决定在哪里放置 print 语句比单步到达代码的关键部分花费更少的时间,即便假设我们知道关键部分在哪里。更重要的是,调试语句留在程序中;调试会话是短暂的。

日志记录确实有其缺点。它会降低应用程序的运行速度。如果过于冗长,可能会导致滚动失明[1]。为了减轻这些担忧,log4j 被设计成可靠、快速和可扩展的。由于日志记录很少是应用程序的主要关注点,因此 log4j API 力求易于理解和使用。

Log4j 2
LOG4J 2 Logo

Log4j 1.x 已被广泛采用并在许多应用程序中使用。然而,经过多年发展它的速度已经慢下来了。由于需要兼容非常旧的 Java 版本,它变得更加难以维护,并最终在 2015 年 8 月到达了其生命周期尽头 🌹。它的替代方案,SLF4J/Logback 对框架进行了许多必要的改进。

Apache Log4j 2 是 Log4j 的升级版,相对于其前身 Log4j 1.x 提供了重大改进。它提供了 Logback 中可用的许多改进,同时修复了 Logback 架构中的一些固有问题。

Log4Net
Apache log4net 库是一个帮助程序员将日志语句输出到各种输出目标的工具。log4net 是优秀的 Apache log4j™ 框架到 Microsoft® .NET 运行时的一个移植。log4net 保持了框架在精神上与最初的 log4j 相似,同时利用了 .NET 运行时的新特性。有关 log4net 的更多信息,请参阅 特性文档。
Apache log4net 项目
Logging Services Logo
log4net 是 Apache 软件基金会的 Apache 日志服务项目的一部分。Logging Services 项目旨在为应用程序调试和审计提供跨语言的日志服务。
Why Log 4?

有些同学可能会对名称中出现的数字 “4” 感到疑惑,但如果你尝试使用英文念出 Log4j 或者 Log4Net 的名称后,相信这个问题就会迎刃而解了。

没错,名称中的 “4” 代表英文单词 "for",因为 “4” 的英文单词 "four" 与 "for" 发音类似。所以,"Log4j" 的含义就是 "Log for Java", 意思是这是一个为 Java 提供日志服务的工具。

这是一种常见的命名方式,通过数字 “4” 来代替 "for", 使得名称更加简洁,也增加了一些趣味性。此外,还有其他的类似命名方式,比如使用 “2” 来代替 "to"。它们都在许多场合内大量使用着。

1、框架

Log4Net 可用于多个框架。对于每个支持的框架,都构建了一个针对该框架的程序集:

  • .NET Standard 1.3 via .NET Core 1.0
  • Microsoft® .NET Framework 1.0
  • Microsoft .NET Framework 1.1
  • Microsoft .NET Framework 2.0
  • Microsoft .NET Framework 3.5
  • Microsoft .NET Framework 4.0
  • Microsoft .NET Framework 4.5
  • Microsoft .NET Framework 3.5 Client Profile
  • Microsoft .NET Framework 4.0 Client Profile
  • Microsoft .NET Compact Framework 1.0
  • Microsoft .NET Compact Framework 2.0
  • Mono 1.0
  • Mono 2.0
  • Mono 3.5
  • Mono 4.0
  • Microsoft Shared Source CLI 1.0
  • CLI 1.0 Compatible

并不是所有的框架都是平等的,一些特性被排除在一些构建(的程序集)之外。有关更多信息,请参阅框架支持文档。

2、Loggers 与 Appenders

Log4Net 有三个主要的组件:loggers, appenderslayouts。这三种类型的组件协同工作使得开发者能够根据消息类型和级别记录日志消息,并在运行时控制这些消息的格式和报告位置。这些组件由控制着 appender 和(将对象转换为字符串的)object renderers 的动作的 filters 辅助。

3、Logger 层次结构

与普通的 System.Console.WriteLine 相比,任何日志 API 的首要优势在于它能够禁用某些日志语句,同时允许其他日志语句不受阻碍地打印。此功能假设日志空间,即所有可能的日志语句的空间,是根据开发人员选择的一些标准进行分类的。

Loggers 是命名实体。Loggers 名称区分大小写,并遵循以下分层命名规则:

层次结构命名

如果一个 logger 名称后跟一个点是后代 logger 名称的前缀,则该 logger 被称为另一个 logger 的祖先。如果在其自身和后代 logger 之间没有祖先,则称其为子 logger 的父 logger。

层次结构的工作方式与 .NET 中的命名空间和类层次结构非常相似。这是非常方便的,我们很快就会看到。

例如:名为 “Foo.Bar” 的 logger 是名为 “Foo.Bar.Baz” 的 logger 的父级。
类似的,“System” 是 “System.Text” 的父级以及 “System.Text.StringBuilder” 的祖先。大多数开发人员应该熟悉这套命名方案。

root logger 位于 logger 层次结构的顶层。它主要有三点不同:

  1. 它总是存在的
  2. 它不能按名称检索
  3. 它总是有一个指定的级别

使用 log4net.LogManager 类的静态方法以检索 loggers。GetLogger 方法将所需 logger 的名称作为参数。如下列所示:

namespace log4net
{public class LogManager{public static ILog GetLogger(string name);public static ILog GetLogger(Type type);}
}

接收 Type 参数的 GetLogger 方法使用完全限定类型名作为要检索的 logger 名称。

这些 GetLogger 方法返回一个 ILog 接口。这是传递给开发人员的 Logger 的表现形式。ILog 接口定义如下:

namespace log4net
{public interface ILog{/* Test if a level is enabled for logging */bool IsDebugEnabled { get; }bool IsInfoEnabled { get; }bool IsWarnEnabled { get; }bool IsErrorEnabled { get; }bool IsFatalEnabled { get; }/* Log a message object */void Debug(object message);void Info(object message);void Warn(object message);void Error(object message);void Fatal(object message);/* Log a message object and exception */void Debug(object message, Exception t);void Info(object message, Exception t);void Warn(object message, Exception t);void Error(object message, Exception t);void Fatal(object message, Exception t);/* Log a message string using the System.String.Format syntax */void DebugFormat(string format, params object[] args);void InfoFormat(string format, params object[] args);void WarnFormat(string format, params object[] args);void ErrorFormat(string format, params object[] args);void FatalFormat(string format, params object[] args);/* Log a message string using the System.String.Format syntax */void DebugFormat(IFormatProvider provider, string format, params object[] args);void InfoFormat(IFormatProvider provider, string format, params object[] args);void WarnFormat(IFormatProvider provider, string format, params object[] args);void ErrorFormat(IFormatProvider provider, string format, params object[] args);void FatalFormat(IFormatProvider provider, string format, params object[] args);}
}

loggers 也许 被分配了级别。级别是 log4net.Core.Level 类的实例。以下级别按优先级的先后顺序定义:

  • ALL
  • DEBUG
  • INFO
  • WARN
  • ERROR
  • FATAL
  • OFF

如果给定的 logger 没有被分配级别,那么它将从具有指定级别的最接近的祖先处继承一个级别。更正式地:

级别继承
给定 logger X 的继承级别等于 logger 层次结构中的第一个非空级别,从 X 开始,在层次结构中向上进行,直至 root logger。

为了确保所有的 logger 最终都可以继承一个级别,root logger 总是有一个分配的级别。其默认值是 DEBUG。

下面是四个表,其中包含各种分配的级别值和根据上述规则继承级别结果。

Logger 名称分配的级别继承的级别
rootProotProot
XnoneProot
X.YnoneProot
X.Y.ZnoneProot

上例一中,只有 root logger 被分配了级别。该级别值,即 Proot,由其他 logger X、X.Y、X.Y.Z 继承。

Logger 名称分配的级别继承的级别
rootProotProot
XPxPx
X.YPxyPxy
X.Y.ZPxyzPxyz

上例二中,所有的 logger 都有分配的级别值。所以不需要级别继承

Logger 名称分配的级别继承的级别
rootProotProot
XPxPx
X.YnonePx
X.Y.ZPxyzPxyz

上例三中,root、X 以及 X.Y.Z logger 分别被分配为级别 Proot、Px 以及 Pxyz。logger X.Y 从其父级 X 处继承其级别值。

Logger 名称分配的级别继承的级别
rootProotProot
XPxPx
X.YnonePx
X.Y.ZnonePx

上例四中,root 以及 X logger 分别被分配为级别 Proot 以及 Px。logger X.Y 以及 X.Y.Z 从最近的具有指定级别的父级 X 处继承其级别值。

日志记录请求是(通过 log4net.ILog)调用 logger 实例的一个打印方法发出的。这些打印方法是 DebugInfoWarnErrorFatal

根据定义,打印方法确定日志记录请求的级别。例如:如果 log 是一个 logger 实例,则语句 log.Info("..") 是一个级别为 INFO 的日志请求。

如果日志记录请求的级别高于或等于其 logger 的级别,则说该日志记录请求已启用。否则,请求将被禁用。没有指定级别的 logger 将从层次结构中继承一个级别。这条规则总结如下:

基本选择规则
如果 L ≥ K,则启用级别为 K(指定的或继承的,视情况而定)的 logger 中的级别为 L 的日志请求。

这条规则是 log4net 的核心。它假设级别是有序的。对于标准级别,我们有 DEBUG < INFO < WARN < ERROR < FATAL。

使用相同的名称调用 log4net.LogManager.GetLogger 方法将始终返回对完全相同的 logger 对象的引用。

例如,在

ILog x = LogManager.GetLogger("wombat");
ILog y = LogManager.GetLogger("wombat");

中,xy 引用完全相同的 logger 对象。

因此,这使得配置一个 logger 并随后在不传递引用的前提下在代码中的另外一个地方检索相同的实例成为可能。log4net logger 可以按任何顺序进行创建和配置,这与生物学上的亲子关系(父母总是先于孩子)存在根本矛盾。特别是,“parent” logger 将找到并链接到它的后代,即使它是在它们之后实例化的。

log4net 环境的配置通常在应用程序初始化时完成。首选的方法是读取配置文件。稍后将讨论这种方法。

通过软件组件,log4net 使得 loggers 命名变得非常容易。这可以通过在每个类中静态实例化一个 logger 来实现,logger 的名称等于类的完全限定名称。这是定义 logger 的一种有用且直接的方法。由于日志输出带有生成 logger 的名称,因此这种命名策略可以很容易地识别日志消息的来源。然而,这只是命名 loggers 的一种可能的策略,尽管很常见。log4net 不限制可能的 loggers 集合。开发人员可根据需要自由地命名 loggers。

尽管如此,以 logger 所在的类命名 logger 似乎是迄今为止已知的最佳策略。对于开发人员来说,要明确每个日志消息的来源很简单。最重要的是,它利用应用程序的设计来生成 logger 层次结构的设计。希望应用程序的设计中已经考虑了一些问题。

4、Appenders

基于 logger 选择性地启用或禁用日志记录请求的能力只是其中的一部分。Log4Net 允许日志请求打印到多个目的地。在 Log4Net 中,输出目的地被称为 appender。Appenders 必须实现 log4net.Appenders.IAppender 接口。

在 Log4Net 包中定义了以下 appenders:

类型描述
log4net.Appender.AdoNetAppender使用预处理语句或存储过程将日志事件写入数据库。
log4net.Appender.AnsiColorTerminalAppender将颜色突出显示的日志事件写入一个 ANSI 终端窗口。
log4net.Appender.AspNetTraceAppender将日志事件写入 ASP 跟踪上下文。然后可以在 ASP 页面的末尾或 ASP 跟踪页面上呈现这些内容。
log4net.Appender.BufferingForwardingAppender在将日志事件转发给子 appender 之前缓冲日志事件。
log4net.Appender.ColoredConsoleAppender将日志事件写入应用程序的控制台。事件可以进入标准输出流,也可以进入标准错误流。事件可以为每个级别定义可配置的文本和背景颜色。
log4net.Appender.ConsoleAppender将日志事件写入应用程序的控制台。事件可以进入标准输出流,也可以进入标准错误流。
log4net.Appender.DebugAppender将日志事件写入 .NET 系统。
log4net.Appender.EventLogAppender将日志事件写入 Windows 事件日志。
log4net.Appender.FileAppender将日志事件写入文件系统中的文件。
log4net.Appender.ForwardingAppender将日志事件转发给子 appender。
log4net.Appender.LocalSyslogAppender将日志事件写入本地 syslog 服务(仅限 UNIX)。
log4net.Appender.MemoryAppender将日志事件存储在内存缓冲区中。
log4net.Appender.NetSendAppender将日志事件写入 Windows Messenger 服务。这些消息显示在用户终端的对话框中。
log4net.Appender.OutputDebugStringAppender将日志事件写入调试器。如果应用程序没有调试器,系统调试器将显示该字符串。如果应用程序没有调试器并且系统调试器未激活,则忽略该消息。
log4net.Appender.RemoteSyslogAppender使用 UDP 网络将日志事件写入远程 syslog 服务。
log4net.Appender.RemotingAppender使用 .NET 远程处理将日志事件写入远程处理接收器。
log4net.Appender.RollingFileAppender将日志事件写入文件系统中的文件。RollingFileAppender 可以配置为根据日期或文件大小限制记录多个文件。
log4net.Appender.SmtpAppender将日志事件发送到电子邮件地址。
log4net.Appender.SmtpPickupDirAppender将 SMTP 邮件作为文件写入取件目录。然后,可以通过 SMTP 代理(如 IIS SMTP 代理)读取和发送这些文件。
log4net.Appender.TelnetAppender客户端通过 Telnet 连接以接收日志事件。
log4net.Appender.TraceAppender将日志事件写入 .NET 跟踪系统。
log4net.Appender.UdpAppender使用 UdpClient 将日志事件作为无连接 UDP 数据报发送到远程主机或多播组。

一个 logger 可以附加多个 appender。

给定 logger 的每个启用的日志记录请求将被转发到该 logger 中的所有 appender 以及层次结构中更高的 appender。 换句话说,appenders 是从 logger 层次结构中累加继承的。例如,如果将控制台 appender 添加到 root logger,那么所有启用的日志请求将至少在控制台上打印。如果另外一个文件 appender 被添加到 logger X 中,那么对 XX 的子级启用的日志记录请求将在文件和控制台上打印。通过将 logger 上的 additivity 设置为 false,可以覆盖此默认行为,以便不再添加 appender 累积。

支配 appender 累加的规则总结如下:

appender 可加性

logger X 的日志语句的输出将转到 X 及其祖先中的所有 appenders。这就是术语 "appender additivity" 的含义。

但是,如果 logger X 的祖先,比如 Y,将 additivity 标志设置为 false,则 X 的输出将定向到 X 及其上至 Y(包括 Y)的祖先中的所有 appenders;但不定向到 Y 的任何祖先中的 appenders。

默认情况下,loggers 将其 additivity 标志设置为 true

下表展示了一个示例:

Logger 名称添加的 AppendersAdditivity 标志输出目标说明
rootA1不适用A1没有默认的 appender 附加到 root(即 root 默认是没有附加任何 appender 的,这里我们显示地为其配置了一个 A1 appender)
xA-x1, A-x2trueA1, A-x1, A-x2“x” 和 root 的 appenders
x.ynonetrueA1, A-x1, A-x2“x” 和 root 的 appenders
x.y.zA-xyz1trueA1, A-x1, A-x2, A-xyz1“x.y.z”、“x” 和 root 中的 appenders
securityA-secfalseA-sec因为 additivity 标志设置为 false,因此没有 appender 累积
security.accessnonetrueA-sec只有 “security” 的 appenders,因为 “security” 中的 additivity 标志设置为了 false

5、Filters

appenders 可以过滤传递给它们的事件。可以在配置中指定 filters,以便对通过不同 appenders 记录的事件进行精细控制。

最简单的控制形式是在 appender 上指定一个 Threshold(阈值)。其工作原理是只记录级别大于或等于阈值的事件。

更复杂和自定义的事件过滤可以使用在每个 appender 上定义的过滤器链来完成。filters 必须实现 log4net.Filter.IFilter 接口。

在 Log4Net 包中定义了以下 filters:

类型描述
log4net.Filter.DenyAllFilter丢弃所有日志事件。
log4net.Filter.LevelMatchFilter和事件的级别完全匹配。
log4net.Filter.LevelRangeFilter对一系列级别进行匹配。
log4net.Filter.LoggerMatchFilter与记录器名称的开头匹配。
log4net.Filter.PropertyFilter匹配特定属性值的子字符串。
log4net.Filter.StringMatchFilter匹配事件消息中的子字符串。

filters 可以配置为根据匹配接受或拒绝事件。

6、Layouts

通常情况下,用户不仅希望自定义输出目的地,还希望自定义输出格式。这是通过将 layout 与 appender 关联来实现的。layout 负责根据用户的意愿格式化日志记录请求;而 appender 负责将格式化后的输出发送到目的地。PatternLayout 是标准 log4net 分发的一部分,它允许用户根据类似于 C 语言 printf 函数的转换模式指定输出格式。

例如,带有转换模式 “%timestamp [%thread] %-5level %logger - %message%newline” 的 PatternLayout 将输出类似于以下内容:

176 [main] INFO  Com.Foo.Bar - Located nearest gas station.

第一个字段是程序开始后经过的毫秒数。第二个字段是发出日志请求的线程。第三个字段是日志语句的级别。第四个字段是与日志请求关联的 logger 的名称。“-”后面的文本是语句的消息。

log4net 包中包含以下 layouts:

类型描述
log4net.Layout.ExceptionLayout呈现来自日志事件的异常文本。
log4net.Layout.PatternLayout根据一组灵活的格式化标志来格式化日志事件。
log4net.Layout.RawTimeStampLayout从日志事件中提取时间戳。
log4net.Layout.RawUtcTimeStampLayout以通用时间(UTC)从日志事件中提取时间戳。
log4net.Layout.SimpleLayout非常简单地格式化日志事件:[level] - [message]
log4net.Layout.XmlLayout将日志事件格式化为 XML 元素。
log4net.Layout.XmlLayoutSchemaLog4j将日志事件格式化为符合 log4j 事件文件类型定义的 XML 元素。

7、Object Renderers

同样重要的是,log4net 将根据用户指定的标准呈现日志消息的内容。例如,如果您经常需要记录橙子(当前项目中使用的对象类型),那么您可以注册一个 OrangeRenderer,每当需要记录橙子时就会调用它。

对象呈现遵循类层次结构。例如,假设橙子是水果,如果你注册了一个 FruitRenderer,那么包括橙子在内的所有水果都将由 FruitRenderer 渲染,除非你注册了一个特定于橙子的 OrangeRenderer。

object renderers 必须实现 log4net.ObjectRenderer.IObjectRenderer 接口。

请注意,ObjectRenderers 不会被 DebugFormat、InfoFormat、WarnFormat、ErrorFormat 和 FatalFormat 方法使用。


脚注

[1]:所谓“滚动失明”,是指当日志信息过于冗长时,程序员查找日志需要滚动查看大量的日志。而相信大部分小伙伴应该体会过,在大量冗长的信息内快速滚动时,我们很难从中找到有用的信息,就像是“失明”了一样。这是由于人的注意力和视觉搜索能力是有限的,当面对大量快速变化的信息时,可能会错过重要的细节。这就是所谓的"滚动失明”。


下一篇


http://www.ppmy.cn/news/1142242.html

相关文章

reactjs开发环境搭建

Reactjs是一个前端web页面应用开发框架工具集&#xff0c;其支持前端构建页面以及后端构建页面两种常用的开发场景&#xff0c;其中&#xff0c;支持reactjs的开发框架包括next.js、remix、gatsby以及其他&#xff0c;本文主要描述next.js开发环境的搭建&#xff0c;next.js是一…

HTML+CSS跑马灯/流光字效果实例代码

简介 HTMLCSS跑马灯/流光字效果实例代码 演示 代码 css <style type"text/css">body {margin: 0;padding: 0;background-color: #2f2424;}div {margin: 400px auto;font-size: 40px;text-align: center;}p {margin: 0;background: -webkit-linear-gradient(…

二、图像处理

待完善 一、图片缩放 import org.bytedeco.opencv.global.opencv_imgcodecs; import org.bytedeco.opencv.global.opencv_imgproc; import org.bytedeco.opencv.opencv_core.Mat; import org.bytedeco.opencv.opencv_core.Size;public class ImageResizer {public static voi…

leetcode 502. IPO

假设 力扣&#xff08;LeetCode&#xff09;即将开始 IPO 。为了以更高的价格将股票卖给风险投资公司&#xff0c;力扣 希望在 IPO 之前开展一些项目以增加其资本。 由于资源有限&#xff0c;它只能在 IPO 之前完成最多 k 个不同的项目。帮助 力扣 设计完成最多 k 个不同项目后…

yolov5+bytetrack算法在华为NPU上进行端到端开发

自从毕业后开始进入了华为曻腾生态圈&#xff0c;现在越来越多的公司开始走国产化路线了&#xff0c;现在国内做AI芯片的厂商比如&#xff1a;寒武纪、地平线等&#xff0c;虽然我了解的不多&#xff0c;但是相对于瑞芯微这样的AI开发板来说&#xff0c;华为曻腾的生态比瑞芯微…

第4章 决策树

文章目录 4.1 基本流程4.2 划分选择4.2.1 信息增益4.2.2 增益率4.2.3 基尼指数 4.3 剪枝处理4.4 连续与缺失值4.5 多变量决策树4.6 阅读材料 4.1 基本流程 决策树也称判定树&#xff0c;是一类常见的机器学习方法。决策树是基于树结构来进行决策的&#xff0c;这恰是人类在面临…

Python实现RNN算法对MFCC特征的简单语音识别

Python实现RNN算法对MFCC特征的简单语音识别 1、实现步骤 借助深度学习库 TensorFlow/Keras 来构建模型 1.对标签进行编码,将文本标签转换为整数标签。 2.对 MFCC 特征数据进行填充或截断,使其长度一致,以便于输入到 RNN 模型中 3.如果是二维数据需要转成三维: Simpl…

电商数据的采集标准

品牌在做控价或者数据分析时&#xff0c;都离不开对数据的采集&#xff0c;只有准确的进行了数据采集&#xff0c;才能保证控价结果和分析结果的准确性。所以对于电商数据的采集&#xff0c;其标准也相对比较高。 力维网络有专业稳定的电商数据采集系统&#xff0c;可以多平台、…

Python是神经网络的最佳语言,这里有五个原因

在当今数字时代&#xff0c;神经网络和深度学习已经成为了人工智能的前沿领域&#xff0c;引领着科技革命的浪潮。而在这场变革中&#xff0c;有一个编程语言傲视群雄&#xff0c;几乎无人能敌&#xff0c;那就是Python。 你可能会好奇&#xff0c;为什么Python成为了神经网络…

HarmonyOS/OpenHarmony原生应用开发-华为Serverless云端服务支持说明(一)

云端服务的实现是HarmonyOS/OpenHarmony原生应用开发的一个重要的环节&#xff0c;如果用户端是鸿蒙原生应用&#xff0c;但是服务端即云端还是基于传统的各种WEB网络框架、数据库与云服务器&#xff0c;那么所谓的原生应用开发实现的数据即后端服务是和以前、现在的互联网、移…

SpringCloud学习二

基本介绍&#xff1a; Eureka Server&#xff08;Eureka 服务端&#xff09;是Netflix开源的一款用于构建分布式系统中的服务发现和注册中心的组件。它在微服务架构中扮演着关键的角色&#xff0c;允许不同的微服务应用程序注册自己&#xff0c;并查询其他服务的位置信息&…

DCE/RPC协议详解之-数据包请求响应过程

在windows的域环境中有非常多的协议和服务是基于DCE/RPC协议进行实现的,例如NETLOGON,LSA,SAMR,DSSETUP等。因此在 windows的环境下会大量的遇到DCE/RPC协议,因此有必要对该协议有一个初步的了解,这样的话在遇到对应的数据包,则能够比较清楚的还原数据包中发生了什么。本…

【正点原子STM32连载】 第四十章 DAC输出三角波实验 摘自【正点原子】APM32F407最小系统板使用指南

1&#xff09;实验平台&#xff1a;正点原子stm32f103战舰开发板V4 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id609294757420 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html## 第四…

数据结构-二叉查找树(BST)

二叉查找树 需要满足这些规则&#xff1a; 左子节点小于父节点右子节点大于父节点 查找的效率 非常好&#xff0c;每次都能根据大小去舍弃另一半的分支&#xff0c;极大的减少的比对次数 具体的性能&#xff0c;取决于树的层数和平衡程度。 BST树的节点 struct Node {No…

简易的贪吃蛇小游戏(以后或许会更新)C++/C语言

第一版&#xff1a; #include <stdio.h> #include <conio.h> #include <stdlib.h> #include <windows.h>#define WIDTH 20 #define HEIGHT 20int gameOver; int score; int x, y; // 蛇头的坐标 int fruitX, fruitY; // 食物的坐标 int tailX[100], t…

【动手学深度学习】课程笔记 00-03 深度学习介绍及环境配置

目录 00-01 课程安排 02 深度学习介绍 深度学习实际应用的流程 完整的故事 03 环境配置 00-01 课程安排 1. 学习了这门课&#xff0c;你将收获什么&#xff1f; 深度学习的经典和最新模型&#xff1a;LeNet&#xff0c;ResNet&#xff0c;LSTM&#xff0c;BERT&#xff1…

C#WPF属性元素语法应用实例

本文介绍C#WPF属性元素语法应用实例 一、属性元素语法 对于对象元素的某些属性,无法使用特性语法(比如:Background="Blue"),因为无法在特性语法的引号和字符串限制内充分地表达提供属性值所必需的对象或信息。 对于这些情况,可以使用另一个语法,即属性元素语…

箭头函数和回调函数

箭头函数 本质是一种函数。 箭头函数就是匿名函数&#xff0c;是简化了的匿名函数&#xff0c;他的调用方法和匿名函数一样 &#xff08;&#xff09;>{console.log("你好")} //1.箭头函数常见用法 let fn1(a,b)>{return ab;} //2.如果箭头函数没有参数&am…

OpenCV3-Python(5)直方图

直方图的一些术语和细节&#xff1a; dims&#xff1a;需要统计的特征数目。在统计灰度图中&#xff0c;dims1&#xff0c;因为仅仅统计了灰度值。bins&#xff1a;每个特征空间子区段的数目&#xff0c;可译为“直条”或“组距”&#xff0c;在上例bins16。range&#xff1a;…

Android Studio修改模拟器AVD Manger目录

Android Studio修改虚拟机AVD Manger目录 1、在AS的设备管理器Device Manager中删除原来创建的所有虚拟机&#xff08;Android Virtual Device&#xff09;&#xff1b; 2、新建一个自定义的AVD目录&#xff0c;例如&#xff1a;D:\Android\AndroidAVD 3、在高级系统设置中增加…
最新文章