百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

你用了这么久的Log4j2日志框架,真的对它有自己的理解吗?

ccwgpt 2024-10-01 08:13 38 浏览 0 评论

1.日志框架

日志接口(slf4j)

slf4j是对所有日志框架制定的一种规范、标准、接口,并不是一个框架的具体的实现,因为接口并不能独立使用,需要和具体的日志框架实现配合使用(如log4j、logback)

日志实现(log4j、logback、log4j2)

  • log4j是apache实现的一个开源日志组件
  • logback同样是由log4j的作者设计完成的,拥有更好的特性,用来取代log4j的一个日志框架,是slf4j的原生实现
  • log4j2是log4j 1.x和logback的改进版,据说采用了一些新技术(无锁异步、等等),使得日志的吞吐量、性能比log4j 1.x提高10倍,并解决了一些死锁的bug,而且配置更加简单灵活。

2.为什么需要日志接口,直接使用具体的实现不就行了吗?

接口用于定制规范,可以有多个实现,使用时是面向接口的(导入的包都是slf4j的包而不是具体某个日志框架中的包),即直接和接口交互,不直接使用实现,所以可以任意的更换实现而不用更改代码中的日志相关代码。

比如:slf4j定义了一套日志接口,项目中使用的日志框架是logback,开发中调用的所有接口都是slf4j的,不直接使用logback,调用是 自己的工程调用slf4j的接口,slf4j的接口去调用logback的实现,可以看到整个过程应用程序并没有直接使用logback,当项目需要更换更加优秀的日志框架时(如log4j2)只需要引入Log4j2的jar和Log4j2对应的配置文件即可,完全不用更改Java代码中的日志相关的代码logger.info(“xxx”),也不用修改日志相关的类的导入的包(import org.slf4j.Logger; import org.slf4j.LoggerFactory;)

使用日志接口便于更换为其他日志框架

log4j、logback、log4j2都是一种日志具体实现框架,所以既可以单独使用也可以结合slf4j一起搭配使用。

本文使用Log4j2作为slf4j的具体实现,引入的包如下:

<dependency>
????<groupId>org.slf4j</groupId>
????<artifactId>slf4j-api</artifactId>
????<version>1.7.25</version>
</dependency>
<dependency>
????<groupId>org.apache.logging.log4j</groupId>
????<artifactId>log4j-slf4j-impl</artifactId>
????<version>2.11.0</version>
</dependency>
<dependency>
????<groupId>org.apache.logging.log4j</groupId>
????<artifactId>log4j-core</artifactId>
????<version>2.11.0</version>
</dependency>
<dependency>
????<groupId>org.apache.logging.log4j</groupId>
????<artifactId>log4j-api</artifactId>
????<version>2.11.0</version>
</dependency>

3.log4j2日志级别

从大到小依次是: off, fatal, error, warn, info, debug, trace, all

由于我们使用的是slf4j接口包,该接口包中只提供了未标有删除线的日志级别的输出。

4.log4j2配置文件的优先级

Log4j will inspect the log4j.configurationFile system property and, if set, will attempt to load the configuration using the ConfigurationFactory that matches the file extension.

If no system property is set the properties ConfigurationFactory will look for log4j2-test.properties in the classpath.

If no such file is found the YAML ConfigurationFactory will look for log4j2-test.yaml or log4j2-test.yml in the classpath.

If no such file is found the JSON ConfigurationFactory will look for log4j2-test.json or log4j2-test.jsn in the classpath.

If no such file is found the XML ConfigurationFactory will look for log4j2-test.xml in the classpath.

If a test file cannot be located the properties ConfigurationFactory will look for log4j2.properties on the classpath.

If a properties file cannot be located the YAML ConfigurationFactory will look for log4j2.yaml or log4j2.yml on the classpath.

If a YAML file cannot be located the JSON ConfigurationFactory will look for log4j2.json or log4j2.jsn on the classpath.

If a JSON file cannot be located the XML ConfigurationFactory will try to locate log4j2.xml on the classpath.

If no configuration file could be located the DefaultConfiguration will be used. This will cause logging output to go to the console.

5.对于log4j2配置文件的理解

配置文件结构:


6.对于Appender的理解

简单说Appender就是一个管道,定义了日志内容的去向(保存位置)。

配置一个或者多个Filter,Filter的过滤机制和Servlet的Filter有些差别,下文会进行说明。

  • 配置Layout来控制日志信息的输出格式。
  • 配置Policies以控制日志何时(When)进行滚动。
  • 配置Strategy以控制日志如何(How)进行滚动。

7.对于Logger的理解

简单说Logger就是一个路由器,指定类、包中的日志信息流向哪个管道,以及控制他们的流量(日志级别)

8.log4j2配置文件框架

配置文件格式

<?xml?version="1.0"?encoding="UTF-8"?>

<Configuration>

????<Appenders>

????????<Appender>
????????????<Filters>
????????????????<LevelRangeFilter?minLevel="..."?maxLevel="..."?onMatch="..."?onMismatch="..."/>
????????????</Filters>

????????????<PatternLayout?pattern="..."?charset="..."/>

????????????<Policies>
????????????????<CronTriggeringPolicy?schedule="..."/>
????????????????<SizeBasedTriggeringPolicy?size="..."/>
????????????????<TimeBasedTriggeringPolicy?/>
????????????</Policies>
????????</Appender>

????????<Appender>
????????????//?...
????????</Appender>

????</Appenders>

????<Loggers>

????????<Logger>
????????????<AppenderRef?ref="...">
????????</Logger>

????????<Root>
????????????<AppenderRef?ref="...">
????????</Root>

????</Loggers>

</Configuration>

9.Appender标签的实现类

其实这些标签都是类名或者类名去掉后缀。

Appender的常用的实现类有:

  • ConsoleAppender(Console)
  • FileAppender(File)、RandomAccessFileAppender(RandomAccessFile)
  • RollingFileAppender(RollingFile)、RollingRandomAccessFileAppender(RollingRandomAccessFile)

打开这些实现类的源码,你一定会恍然大明白,括号中的是实现类在log4j2.xml配置文件中的标签名。

10.ConsoleAppender(Console)

该实现类会把日志输出到控制台中。

它有两种输出方式:

  • SYSTEM_OUT(System.out)
  • SYSTEM_ERR(System.err)

如果不配置,默认使用SYSTEM_OUT进行输出。括号中是调用的方法。

简单示例:

<?xml?version="1.0"?encoding="UTF-8"?>
<Configuration?name="baseConf"?status="warn"?monitorInterval="30">

????<Appenders>

????????<Console?name="Console"?target="SYSTEM_OUT">
????????????<!--?格式化日志?-->
????????????<PatternLayout?pattern="%d{HH:mm:ss.SSS}?[%t]?%-5level?%logger{36}?-?%msg%n"?charset="UTF-8"/>
????????</Console>

????</Appenders>

????<Loggers>

????????<!--?level默认为error?-->
????????<Root?level="info">
????????????<!--?这里引用了Appenders标签中的name值?-->
????????????<AppenderRef?ref="RollingFile"/>
????????</Root>

????</Loggers>

</Configuration>

其它属性可以参见官方文档:

http://logging.apache.org/log4j/2.x/manual/appenders.html#ConsoleAppender

10-1.FileAppender(File)、RandomAccessFileAppender(RandomAccessFile)

相同点:写入日志信息到文件

不同点:使用的I/O实现类不同,前者使用FileOutputStream,后者使用RandomAccessFile。

官方文档说是在bufferedIO=true(默认是true)的情况下后者比前者性能提升20% ~ 200%,不明觉厉,就用后者吧。

简单示例:

<?xml?version="1.0"?encoding="UTF-8"?>
<Configuration?name="baseConf"?status="warn"?monitorInterval="30">

????<Appenders>

????????<RandomAccessFile?name="File"?fileName="logs/app.log"?immediateFlush="false">
????????????<PatternLayout?pattern="%d{HH:mm:ss.SSS}?[%t]?%-5level?%logger{36}?-?%msg%n"?charset="UTF-8"/>
????????</RandomAccessFile>

????</Appenders>

????<Loggers>

????????<Root?level="info">
????????????<AppenderRef?ref="File"/>
????????</Root>

????</Loggers>

</Configuration>

常用属性:

  • fileName:来指定文件位置,文件或目录不存在则会自动创建。
  • immediateFlush:是否每次写入都要立刻刷新到硬盘中。默认true,如果使用默认值可能会影响性能。

其它属性可以参见官方文档:

http://logging.apache.org/log4j/2.x/manual/appenders.html#RandomAccessFileAppender

10-2.RollingFileAppender(RollingFile)、RollingRandomAccessFileAppender(RollingRandomAccessFile)

这一对之间的区别与上一对之间的区别是一样的。

上一对的实现类不能进行日志滚动,所谓日志滚动就是当达到设定的条件后,日志文件进行切分。

比如:工程师想让系统中的日志按日进行切分,并且按月归档。

这时候这一对的作用就体现出来了。

简单示例:

<?xml?version="1.0"?encoding="UTF-8"?>
<Configuration?name="baseConf"?status="warn"?monitorInterval="30">

????<Appenders>

????????<RollingRandomAccessFile?name="File"?fileName="logs/app.log"
?????????????????????????????????filePattern="logs/${date:hh-mm}/%d{hh-mm-ss}.app.%i.log"?>
????????????<PatternLayout?pattern="%d{HH:mm:ss.SSS}?[%t]?%-5level?%logger{36}?-?%msg%n"?charset="UTF-8"/>

????????????<Policies>
????????????????<!--?每?5s?翻滚一次?-->
????????????????<CronTriggeringPolicy?schedule="0/5?*?*?*?*??"?/>
????????????????<SizeBasedTriggeringPolicy?size="10?MB"/>
????????????</Policies>

????????????<DefaultRolloverStrategy?max="10"?/>

????????</RollingRandomAccessFile>

????</Appenders>

????<Loggers>

????????<Root?level="info">
????????????<AppenderRef?ref="File"/>
????????</Root>

????</Loggers>

</Configuration>

1.filePattern:指定了日志滚动之后的文件命名格式,至于其中的{date:hh-mm}表达式下文介绍。

2.DefaultRolloverStrategy:指定了如何(How)进行翻滚,并且指定了最大翻滚次数(影响%i参数值),超过次数之后会按照相应的规则删除旧日志。

3.Policies: 这里就是规定了何时进行滚动(When),可以有多个Policy。

  • CronTriggeringPolicy设置了每 5s 进行一次翻滚
  • SizeBasedTriggeringPolicy设置了的话,如果当前文件超过了10MB,但是文件的名字还没有进行翻滚(建立新文件),那么就会用%i的方式进行翻滚。

10-3.翻滚示例

app.log

第一次翻滚:app.log app.1.log // app.log -> app.1.log
第二次翻滚:app.log app.1.log app.2.lop // app.log -> app.2.log
第三次翻滚:app.log app.1.log app.2.lop app.3.lop // app.log -> app.3.log
第四次翻滚:app.log app.1.log app.2.lop app.3.lop app.4.lop // app.log -> app.4.log

一直到设定的翻滚次数10之后,会把旧的日志内容覆盖。

app.2.lop?->?app.1.lop
app.3.lop?->?app.2.lop
...
app.10.lop?->?app.9.lop
app.log?->?app.10.lop

一直这样循环下去,直到创建新文件。

11.Filters

Filters决定日志事件能否被输出。过滤条件有三个值:ACCEPT(接受),DENY(拒绝),NEUTRAL(中立)。

11-1.常用的Filter实现类有

  • LevelRangeFilter
  • TimeFilter
  • ThresholdFilter

11-2.上文中提到log4j2中的Filter与Servlet中的有差别。那么有什么差别呢?

简单说就是log4j2中的过滤器ACCEPT和DENY之后,后续的过滤器就不会执行了,只有在NEUTRAL的时候才会执行后续的过滤器。

11-3.简单示例

测试代码:

public?class?LogMain?{

????private?static?Logger?logger?=?LoggerFactory.getLogger(LogMain.class);

????public?static?void?main(String[]?args)?throws?Exception?{

????????logger.trace("trace?Msg.");
????????logger.debug("debug?Msg.");
????????logger.info("info?Msg.");
????????logger.warn("warn?Msg.");
????????logger.error("error?Msg.");

????}

}

配置文件:

<?xml?version="1.0"?encoding="UTF-8"?>
<Configuration?name="baseConf"?status="warn"?monitorInterval="30">

????<Appenders>

????????<Console?name="Console">

????????????<!--
????????????????设置?onMismatch="NEUTRAL"?可以让日志经过后续的过滤器
????????????????最后一个过滤器建议设置 onMismatch="DENY", 不然日志就输出了。
????????????-->
????????????<Filters>

????????????????<!--?从大到小:error, warn, info, debug, trace -->
????????????????<LevelRangeFilter?minLevel="error"?maxLevel="info"?onMatch="ACCEPT"?onMismatch="NEUTRAL"?/>

????????????????<!--?只允许在每天的?8点~8点半?之间输出日志?-->
????????????????<TimeFilter?start="08:00:00"?end="08:30:00"?onMatch="ACCEPT"?onMismatch="DENY"?/>
????????????</Filters>

????????????<PatternLayout?pattern="%d{HH:mm:ss.SSS}?[%t]?%-5level?%logger{36}?-?%msg%n"?charset="UTF-8"/>
????????</Console>

????</Appenders>

????<Loggers>

????????<Root?level="info">
????????????<AppenderRef?ref="Console"/>
????????</Root>

????</Loggers>

</Configuration>

输出结果:

17:51:53.546?[main]?INFO??me.master.snail.log.LogMain?-?info?Msg.
17:51:53.548?[main]?WARN??me.master.snail.log.LogMain?-?warn?Msg.
17:51:53.548?[main]?ERROR?me.master.snail.log.LogMain?-?error?Msg.

如果当前时间不是 8点~8点半 之间,那么没有日志会输出。

这里的info Msg.、warn Msg.和error Msg.为什么会输出呢?

是因为LevelRangeFilter对它们进行了ACCEPT,而剩下的trace Msg.和debug Msg.则会经过下一个过滤器,然后依次类推。

12.PatternLayout

这是常用的日志格式化类,其它日志格式化类很少用。

关于其它日志类,可以打开PatternLayout类,找到其父类AbstractStringLayout, 看父类的实现类有哪些。

简单示例:

<PatternLayout?pattern="%d{HH:mm:ss.SSS}?[%t]?%-5level?%logger{36}?-?%msg%n"?charset="UTF-8"/>

授人以鱼不如授人以渔。关于pattern的格式点击

http://logging.apache.org/log4j/2.x/manual/layouts.html#PatternLayout

具体的其它属性可以看源码也可以参考官方文档。

13.Policy & Strategy

上文也说了,Policy是用来控制日志文件何时(When)进行滚动的;Strategy是用来控制日志文件如何(How)进行滚动的。

如果配置的是RollingFile或RollingRandomAccessFile,则必须配置一个Policy。

如果想按月归档,按日切分日志,然后

13-1.Policy常用的实现类:

  • SizeBasedTriggeringPolicy
  • CronTriggeringPolicy
  • TimeBasedTriggeringPolicy

13-1-1.SizeBasedTriggeringPolicy

根据日志文件的大小进行滚动。

<SizeBasedTriggeringPolicy?size="10MB"/>

单位有:KB,MB,GB

13-1-2.CronTriggeringPolicy

使用Cron表达式进行日志滚动,很灵活。

<CronTriggeringPolicy?schedule="0/5?*?*?*?*??"?/>

13-1-3.TimeBasedTriggeringPolicy

这个滚动策略依赖于filePattern中配置的最具体的时间单位,根据最具体的时间单位进行滚动。

这种方式比较简洁。CronTriggeringPolicy策略更强大。

简单示例:

<?xml?version="1.0"?encoding="UTF-8"?>
<Configuration?name="baseConf"?status="warn"?monitorInterval="30">

????<Appenders>

????????<RollingRandomAccessFile?name="File"?fileName="logs/app.log"
?????????????????????????????????filePattern="logs/${date:hh-mm}/%d{hh-mm-ss}.app.%i.log"?>
????????????<PatternLayout?pattern="%d{HH:mm:ss.SSS}?[%t]?%-5level?%logger{36}?-?%msg%n"?charset="UTF-8"/>

????????????<Policies>
????????????????<!--?每?5s?翻滚一次?-->
????????????????<!--<CronTriggeringPolicy?schedule="0/5?*?*?*?*??"?/>-->

????????????????<!--
??????????????????? filePattern中最具体的时间单位是?秒。
????????????????????这里用?TimeBasedTriggeringPolicy?替换?CronTriggeringPolicy

????????????????????注意:modulate属性是指从启动时间开始算5秒,还是从0秒开始算5秒,运行一下就明白了。
????????????????????modulate:?true(默认值)?//?会从启动时间开始算?5秒
????????????????????modulate:?false?//?从?0秒开始算
????????????????-->
????????????????<TimeBasedTriggeringPolicy?interval="5"?modulate="true"/>

????????????????<SizeBasedTriggeringPolicy?size="10?MB"/>
????????????</Policies>

????????????<DefaultRolloverStrategy?max="10"?/>

????????</RollingRandomAccessFile>

????</Appenders>

????<Loggers>

????????<Root?level="info">
????????????<AppenderRef?ref="File"/>
????????</Root>

????</Loggers>

</Configuration>

13-2.Strategy常用的实现类

  • DefaultRolloverStrategy
  • DirectWriteRolloverStrategy

这两个Strategy都是控制如何进行日志滚动的,至于他们的区别我还是不太明白,大佬解释一下吧。

平时大部分用DefaultRolloverStrategy就可以了。

14.Logger

Logger部分就比较简单了,分为两个Logger:

  • Root(必须配置)
  • Logger

简单示例:

<?xml?version="1.0"?encoding="UTF-8"?>
<Configuration?name="baseConf"?status="warn"?monitorInterval="30">

????<Appenders>

????????<Console?name="Console">
????????????<PatternLayout>
????????????????<Pattern>%d?%p?%c{1.}?[%t]?%m%n</Pattern>
????????????</PatternLayout>
????????</Console>

????</Appenders>

????<Loggers>

????????<Root?level="trace">
????????????<AppenderRef?ref="Console"/>
????????????<Filters>
????????????????<LevelRangeFilter?minLevel="error"?maxLevel="info"?onMatch="ACCEPT"?onMismatch="DENY"?/>
????????????</Filters>
????????</Root>

????</Loggers>

</Configuration>

注意:Logger中也可以加过滤器的哟~

14-1.比较重要的问题: 日志重复打印

如果Root中的日志包含了Logger中的日志信息,并且AppenderRef是一样的配置,则日志会打印两次。

注意:有两个条件

  • Root中的日志包含了Logger中的日志信息
  • 且AppenderRef是一样的配置

这时候我们需要使用一个Logger的属性来解决,那就是additivity,其默认值为true,需要配置为false。

<?xml?version="1.0"?encoding="UTF-8"?>
<Configuration?name="baseConf"?status="warn"?monitorInterval="30">

????<Appenders>

????????<Console?name="Console">
????????????<PatternLayout>
????????????????<Pattern>%d?%p?%c{1.}?[%t]?%m%n</Pattern>
????????????</PatternLayout>
????????</Console>

????</Appenders>

????<Loggers>

????????<Logger?name="me.master.snail.log.LogMain"?level="info"?additivity="false">
????????????<AppenderRef?ref="Console"/>
????????</Logger>

????????<Root?level="trace">
????????????<AppenderRef?ref="Console"/>
????????????<Filters>
????????????????<LevelRangeFilter?minLevel="error"?maxLevel="info"?onMatch="ACCEPT"?onMismatch="DENY"?/>
????????????</Filters>
????????</Root>

????</Loggers>

</Configuration>

15.Lookups

这个组件类似于JSTL的EL表达式,或者类似于Spring的SpEL表达式。

具体的语法很简单,这里就不粘贴复制了,查看官方文档:

http://logging.apache.org/log4j/2.x/manual/lookups.html

相信你用半个小时就学会了。

16.示例

为了大家快速开发(方便懒惰的同学),写一些示例。

16-1.输出到控制台

<?xml?version="1.0"?encoding="UTF-8"?>
<Configuration?name="baseConf"?status="warn"?monitorInterval="30">

????<Appenders>

????????<Console?name="Console"?target="SYSTEM_OUT">
????????????<!--?格式化日志?-->
????????????<PatternLayout?pattern="%d{HH:mm:ss.SSS}?[%t]?%-5level?%logger{36}?-?%msg%n"?charset="UTF-8"/>
????????</Console>

????</Appenders>

????<Loggers>

????????<!--?level默认为error?-->
????????<Root?level="info">
????????????<!--?这里引用了Appenders标签中的name值?-->
????????????<AppenderRef?ref="RollingFile"/>
????????</Root>

????</Loggers>

</Configuration>

16-2.输出到单个文件

<?xml?version="1.0"?encoding="UTF-8"?>
<Configuration?name="baseConf"?status="warn"?monitorInterval="30">

????<Appenders>

????????<RandomAccessFile?name="File"?fileName="logs/app.log"?immediateFlush="false">
????????????<PatternLayout?pattern="%d{HH:mm:ss.SSS}?[%t]?%-5level?%logger{36}?-?%msg%n"?charset="UTF-8"/>
????????</RandomAccessFile>

????</Appenders>

????<Loggers>

????????<Root?level="info">
????????????<AppenderRef?ref="File"/>
????????</Root>

????</Loggers>

</Configuration>

16-3.按月归档日志,按日进行切分,限制单文件大小为 500MB, 一天最多生成20个文件,也就是(20 * 500)MB大小的日志

<?xml?version="1.0"?encoding="UTF-8"?>
<Configuration?name="baseConf"?status="warn"?monitorInterval="30">

????<Appenders>

????????<RollingRandomAccessFile?name="File"?fileName="logs/app.log"
?????????????????????????????????filePattern="logs/${date:yyyy-MM}/%d{yyyy-MM-dd}.app.%i.log"?>
????????????<PatternLayout?pattern="%d{HH:mm:ss.SSS}?[%t]?%-5level?%logger{36}?-?%msg%n"?charset="UTF-8"/>

????????????<Policies>
????????????????<TimeBasedTriggeringPolicy?interval="1"?modulate="false"/>
????????????????<SizeBasedTriggeringPolicy?size="500MB"/>
????????????</Policies>

????????????<DefaultRolloverStrategy?max="20"?/>
????????</RollingRandomAccessFile>

????</Appenders>

????<Loggers>

????????<Root?level="info">
????????????<AppenderRef?ref="File"/>
????????</Root>

????</Loggers>

</Configuration>

16-4.限制Spring框架日志的输出级别

<?xml?version="1.0"?encoding="UTF-8"?>
<Configuration?name="baseConf"?status="warn"?monitorInterval="30">

????<Appenders>

????????<RollingRandomAccessFile?name="File"?fileName="logs/app.log"
?????????????????????????????????filePattern="logs/${date:yyyy-MM}/%d{yyyy-MM-dd}.app.%i.log"?>
????????????<PatternLayout?pattern="%d{HH:mm:ss.SSS}?[%t]?%-5level?%logger{36}?-?%msg%n"?charset="UTF-8"/>

????????????<Policies>
????????????????<TimeBasedTriggeringPolicy?interval="1"?modulate="false"/>
????????????????<SizeBasedTriggeringPolicy?size="500MB"/>
????????????</Policies>

????????????<DefaultRolloverStrategy?max="20"?/>
????????</RollingRandomAccessFile>

????</Appenders>

????<Loggers>

????????<!--
????????????限制Spring框架日志的输出级别,其它框架类似配置
????????????或者使用?AppenderRef?标签,将其输出到指定文件中,记得加上?additivity="false"
????????-->
????????<logger?name="org.springframework"?level="INFO"/>

????????<Root?level="info">
????????????<AppenderRef?ref="File"/>
????????</Root>

????</Loggers>

</Configuration>

学会以上这些理解和方法,相信就可以熟练使用了,加油!

相关推荐

自己动手写Android数据库框架_android开发数据库搭建

http://blog.csdn.net/feiduclear_up/article/details/50557590推荐理由关于Android数据库操作,由于每次都要自己写数据库操作,每次还得去...

谷歌开源大模型评测工具LMEval,打通谷歌、OpenAI、Anthropic

智东西编译|金碧辉编辑|程茜智东西5月28日消息,据科技媒体TheDecoder5月26日报道,当天,谷歌正式发布开源大模型评测框架LMEval,支持对GPT-4o、Claude3.7...

工信部:着力推动大模型算法、框架等基础性原创性的技术突破

工信部新闻发言人今日在发布会上表示,下一步,我们将坚持突出重点领域,大力推动制造业数字化转型,推动人工智能创新应用。主要从以下四个方面着力。一是夯实人工智能技术底座。通过科技创新重大项目,着力推动大模...

乒乓反复纠结“框架不稳定”的三个小误区

很多球友由于对框架的认知不清晰,往往会把“框架不稳定”当成一种心理负担,从而影响学球进度,其典型状态就是训练中有模有样,一旦进入实战,就像被捆住了手脚。通过训练和学习,结合“基本功打卡群”球友们交流发...

前AMD、英特尔显卡架构师Raja再战GPU,号称要全面重构堆栈

IT之家8月5日消息,知名GPU架构师拉贾科杜里(RajaKoduri)此前曾先后在AMD和英特尔的显卡部门担任要职。而在今日,由Raja创立的GPU软件与IP初创企...

三种必须掌握的嵌入式开发程序架构

前言在嵌入式软件开发,包括单片机开发中,软件架构对于开发人员是一个必须认真考虑的问题。软件架构对于系统整体的稳定性和可靠性是非常重要的,一个合适的软件架构不仅结构清晰,并且便于开发。我相...

怪不得别人3秒就知道软考案例怎么做能50+

软考高级统一合格标准必须三科都达到45分,案例分析也一直是考生头疼的一门,但是掌握到得分点,案例能不能50+还不是你们说了算吗?今天就结合架构案例考点,分享实用的备考攻略~一、吃透考点,搭建知识框架从...

UML统一建模常用图有哪些,各自的作用是什么?一篇文章彻底讲透

10万+爆款解析:9大UML图实战案例,小白也能秒懂!为什么需要UML?UML(统一建模语言)是软件开发的“蓝图”,用图形化语言描述系统结构、行为和交互,让复杂需求一目了然。它能:降低沟通成本避...

勒索软件转向云原生架构,直指备份基础设施

勒索软件组织和其他网络犯罪分子正越来越多地将目标对准基于云的备份系统,对久已确立的灾难恢复方法构成了挑战。谷歌安全研究人员在一份关于云安全威胁演变的报告中警告称,随着攻击者不断改进数据窃取、身份泄露和...

ConceptDraw DIAGRAM:释放创意,绘就高效办公新未来

在当今数字化时代,可视化工具已成为提升工作效率和激发创意的关键。ConceptDrawDIAGRAM,作为一款世界顶级的商业绘图软件,凭借其强大的功能和用户友好的界面,正逐渐成为众多专业人士的首选绘...

APP 制作界面设计教程:一步到位_app界面设计模板一套

想让APP界面设计高效落地,无需繁琐流程,掌握“框架搭建—细节填充—体验优化”三步法,即可一步到位完成专业级设计。黄金框架搭建是基础。采用“三三制布局”:将屏幕横向三等分,纵向保留三...

MCP 的工作原理:关键组件_mcp部件

以下是MCP架构的关键组件:MCP主机:像ClaudeDesktop、GitHubCopilot或旅行助手这样的AI智能体,它们希望通过MCP协议访问工具、资源等。MCP主机会...

软件架构_软件架构师工资一般多少

软件架构师自身需要是程序员,并且必须一直坚持做一线程序员。软件架构应该是能力最强的一群程序员,他们通常会在自身承接编程任务的同时,逐渐引导整个团队向一个能够最大化生产力的系统设计方向前进。软件系统的架...

不知不觉将手机字体调大!老花眼是因为“老了吗”?

现在不管是联系、交友,还是购物,都离不开手机。中老年人使用手机的时间也在逐渐加长,刷抖音、看短视频、发朋友圈……看手机的同时,人们也不得不面对“视力危机”——老花眼,习惯眯眼看、凑近看、瞪眼看,不少人...

8000通用汉字学习系列讲座(第046讲)

[表声母字]加(续)[从声汉字]伽茄泇迦枷痂袈笳嘉驾架咖贺瘸(计14字)嘉[正音]标准音读jiā。[辨形]上下结构,十四画。会意形声字,从壴从加,加也表声。注:从壴,字义与鼓乐有关;从加,字义与...

取消回复欢迎 发表评论: