日志組件slf4j介紹及配置詳解

2019獨角獸企業重金招聘Python工程師標準>>> hot3.png

原文出自

1 基本介紹

每一個Java程序員都知道日志對于任何一個Java應用程序尤其是服務端程序是至關重要的,而很多程序員也已經熟悉各種不同的日志庫,如java.util.logging、Apache log4j、logback。但如果你還不知道SLF4J(Simple logging facade for Java)的話,那么是時候在你的項目中學習使用SLF4J了。

SLF4J不同于其他日志類庫,與其它日志類庫有很大的不同。SLF4J(Simple logging Facade for Java)不是一個真正的日志實現,而是一個抽象層( abstraction layer),它允許你在后臺使用任意一個日志類庫。如果是在編寫供內外部都可以使用的API或者通用類庫,那么你真不會希望使用你類庫的客戶端必須使用你選擇的日志類庫。

如果一個項目已經使用了log4j,而你加載了一個類庫,比方說 Apache Active MQ——它依賴于于另外一個日志類庫logback,那么你就需要把它也加載進去。但如果Apache Active MQ使用了SLF4J,你可以繼續使用你的日志類庫而無需忍受加載和維護一個新的日志框架的痛苦。

總的來說,SLF4J使你的代碼獨立于任意一個特定的日志API,這是對于API開發者的很好的思想。雖然抽象日志類庫的思想已經不是新鮮的事物,而且Apache commons logging也已經在使用這種思想了,但SLF4J正迅速成為Java世界的日志標準。讓我們再看幾個使用SLF4J而不是log4j、logback或者java.util.logging的理由。

2 SLF4J對比Log4J,logback和java.util.Logging的優勢

正如我之前說的,在你的代碼中使用SLF4J寫日志語句的主要出發點是使得你的程序獨立于任何特定的日志類庫,依賴于特定類庫可能需要使用不同于你已有的配置,并且導致更多維護的麻煩。除此之外,還有一個SLF4J API的特性是使得我堅持使用SLF4J而拋棄我長期間鐘愛的Log4j的理由,是被稱為占位符(place holder),在代碼中表示為“{}”的特性。占位符是一個非常類似于在Stringformat()方法中的%s,因為它會在運行時被某個提供的實際字符串所替換。這不僅降低了你代碼中字符串連接次數,而且還節省了新建的String對象。通過使用SLF4J,你可以在運行時延遲字符串的建立,這意味著只有需要的String對象才被建立。而如果你已經使用log4j,那么你已經對于在if條件中使用debug語句這種變通方案十分熟悉了,但SLF4J的占位符就比這個好用得多。

這是你在Log4j中使用的方案,但這并不有趣,而且降低了代碼可讀性,因為它增加了不必要的繁瑣重復代碼(boiler-plate code):

if (logger.isDebugEnabled()) {logger.debug("Processing trade with id: " + id + " symbol: " + symbol);
}

另一方面,如果你使用SLF4J的話,你可以得到更簡潔格式的結果,就像以下展示的一樣:

logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);

在SLF4J,我們不需要字符串連接而且不會導致暫時不需要的字符串消耗。取而代之,我們在一個以占位符和參數傳遞實際值構成的模板格式下寫日志信息。你可能會在想萬一我有很多個參數怎么辦?嗯,那么你可以選擇使用變量參數版本的日志方法或者以Object數組傳遞。這是一個相當方便和高效方法的打日志方法。記住,在生產最終日志信息字符串之前,這個方法會檢查一個特定的日志級別是不是打開了,這不僅降低了內存消耗而且預先降低了CPU去處理字符串連接命令的時間。這里是使用SLF4J日志方法的代碼,來自于slf4j-log4j12-1.6.1.jar中的Log4j的適配器類Log4jLoggerAdapter。

public void debug(String format, Object arg1, Object arg2) {if (logger.isDebugEnabled()) {FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());}
}

同時,我們應該知道打日志是對應用程序性能有著很大影響,在生產環節上我們建議只進行必要的日志記錄。

3 使用配置

3.1 maven依賴

<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.21</version>
</dependency>
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.21</version>
</dependency>

3.2 日志系統配置

假設現有如下程序:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class Main {private static final Logger logger = LoggerFactory.getLogger(Main.class);public static void main(String[] args) {int status = 0;if (status == 0) {logger.info("status:{}", status);} else {logger.info("status:{}", status);}logger.info("end!");}
}

可以使用以下兩種方式對日志系統的輸出格式、記錄級別、輸出方式等進行配置。

3.2.1 properties文件方式

log4j.properties:

log4j.rootLogger=info, ServerDailyRollingFile, stdout
log4j.appender.ServerDailyRollingFile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.ServerDailyRollingFile.DatePattern='.'yyyy-MM-dd
log4j.appender.ServerDailyRollingFile.File=logs/notify-subscription.log
log4j.appender.ServerDailyRollingFile.layout=org.apache.log4j.PatternLayout
log4j.appender.ServerDailyRollingFile.layout.ConversionPattern=%d - %m%n
log4j.appender.ServerDailyRollingFile.Append=true
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH\:mm\:ss} %p [%c] %m%n

輸出結果為:

2016-05-12 16:08:21 INFO [club.chuxing.learn.Main] status:0?
2016-05-12 16:08:21 INFO [club.chuxing.learn.Main] end!

3.2.2 xml文件方式

首先pom中添加如下依賴:

<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-core</artifactId><version>1.1.7</version>
</dependency>
<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.1.7</version>
</dependency>
  • ?

logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true"><!-- 應用名稱 --><property name="APP_NAME" value="logtest" /><!--日志文件的保存路徑,首先查找系統屬性-Dlog.dir,如果存在就使用其;否則,在當前目錄下創建名為logs目錄做日志存放的目錄 --><property name="LOG_HOME" value="${log.dir:-logs}/${APP_NAME}" /><!-- 日志輸出格式 --><property name="ENCODER_PATTERN"value="%d{yyyy-MM-dd  HH:mm:ss.SSS} [%thread] %-5level %logger{80} - %msg%n" /><contextName>${APP_NAME}</contextName><!-- 控制臺日志:輸出全部日志到控制臺 --><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><Pattern>${ENCODER_PATTERN}</Pattern></encoder></appender><!-- 文件日志:輸出全部日志到文件 --><appender name="FILE"class="ch.qos.logback.core.rolling.RollingFileAppender"><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>${LOG_HOME}/output.%d{yyyy-MM-dd}.log</fileNamePattern><maxHistory>7</maxHistory></rollingPolicy><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${ENCODER_PATTERN}</pattern></encoder></appender><!-- 錯誤日志:用于將錯誤日志輸出到獨立文件 --><appender name="ERROR_FILE"class="ch.qos.logback.core.rolling.RollingFileAppender"><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>${LOG_HOME}/error.%d{yyyy-MM-dd}.log</fileNamePattern><maxHistory>7</maxHistory></rollingPolicy><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${ENCODER_PATTERN}</pattern></encoder><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><level>WARN</level></filter></appender><!-- 獨立輸出的同步日志 --><appender name="SYNC_FILE"  class="ch.qos.logback.core.rolling.RollingFileAppender"><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>${LOG_HOME}/sync.%d{yyyy-MM-dd}.log</fileNamePattern><maxHistory>7</maxHistory></rollingPolicy><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${ENCODER_PATTERN}</pattern></encoder></appender><logger name="log.sync" level="DEBUG" addtivity="true"><appender-ref ref="SYNC_FILE" /></logger><root><level value="DEBUG" /><appender-ref ref="STDOUT" /><appender-ref ref="FILE" /><appender-ref ref="ERROR_FILE" /></root>
</configuration>

輸出結果為:

2016-05-12 17:08:32.105 [main] INFO club.chuxing.learn.Main - status:0?
2016-05-12 17:08:32.114 [main] INFO club.chuxing.learn.Main - end!

3.3 日志系統配置說明

3.3.1 輸出級別的種類

  • ERROR 為嚴重錯誤 主要是程序的錯誤
  • WARN 為一般警告,比如session丟失
  • INFO 為一般要顯示的信息,比如登錄登出
  • DEBUG 為程序的調試信息

3.3.2 配置日志信息輸出目的地

log4j.appender.appenderName=??

  1. org.apache.log4j.ConsoleAppender(控制臺)
  2. org.apache.log4j.FileAppender(文件)
  3. org.apache.log4j.DailyRollingFileAppender(每天產生一個日志文件)
  4. org.apache.log4j.RollingFileAppender(文件大小到達指定尺寸的時候產生一個新的文件)
  5. org.apache.log4j.WriterAppender(將日志信息以流格式發送到任意指定的地方)

3.3.3 配置日志信息的格式

log4j.appender.appenderName.layout = ??

  1. org.apache.log4j.HTMLLayout(以HTML表格形式布局)
  2. org.apache.log4j.PatternLayout(可以靈活地指定布局模式)
  3. org.apache.log4j.SimpleLayout(包含日志信息的級別和信息字符串)
  4. org.apache.log4j.TTCCLayout(包含日志產生的時間、線程、類別等等信息)

3.3.4 ConsoleAppender選項

Threshold=DEBUG:指定日志消息的輸出最低層次。?
ImmediateFlush=true:默認值是true,意謂著所有的消息都會被立即輸出。?
Target=System.err:默認情況下是System.out,指定輸出控制臺

3.3.5 FileAppender 選項

Threshold=DEBUG:指定日志消息的輸出最低層次。?
ImmediateFlush=true:默認值是true,意謂著所有的消息都會被立即輸出。?
File=mylog.txt:指定消息輸出到mylog.txt文件。?
Append=false:默認值是true,即將消息增加到指定文件中,false指將消息覆蓋指定的文件內容。

3.3.6 RollingFileAppender 選項

Threshold=DEBUG:指定日志消息的輸出最低層次。?
ImmediateFlush=true:默認值是true,意謂著所有的消息都會被立即輸出。?
File=mylog.txt:指定消息輸出到mylog.txt文件。?
Append=false:默認值是true,即將消息增加到指定文件中,false指將消息覆蓋指定的文件內容。?
MaxFileSize=100KB: 后綴可以是KB, MB 或者是 GB. 在日志文件到達該大小時,將會自動滾動,即將原來的內容移到mylog.log.1文件。?
MaxBackupIndex=2:指定可以產生的滾動文件的最大數。

3.3.7 日志信息格式中幾個符號所代表的含義

-X號: X信息輸出時左對齊;?
%p: 輸出日志信息優先級,即DEBUG,INFO,WARN,ERROR,FATAL,?
%d: 輸出日志時間點的日期或時間,默認格式為ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},輸出類似:2002年10月18日 22:10:28,921?
%r: 輸出自應用啟動到輸出該log信息耗費的毫秒數?
%c: 輸出日志信息所屬的類目,通常就是所在類的全名?
%t: 輸出產生該日志事件的線程名?
%l: 輸出日志事件的發生位置,相當于%C.%M(%F:%L)的組合,包括類目名、發生的線程,以及在代碼中的行數。舉例:Testlog4.main (TestLog4.java:10)?
%x: 輸出和當前線程相關聯的NDC(嵌套診斷環境),尤其用到像java servlets這樣的多客戶多線程的應用中。?
%%: 輸出一個”%”字符?
%F: 輸出日志消息產生時所在的文件名稱?
%L: 輸出代碼中的行號?
%m: 輸出代碼中指定的消息,產生的日志具體信息?
%n: 輸出一個回車換行符,Windows平臺為”\r\n”,Unix平臺為”\n”輸出日志信息換行

一個示例配置文件

log4j.debug=true   
log4j.rootLogger=DEBUG,D,Elog4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File = logs/logs.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = DEBUG
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%nlog4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = logs/error.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = ERROR
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

過濾器?
過濾器,執行一個過濾器會有返回個枚舉值,即DENY,NEUTRAL,ACCEPT其中之一。返回DENY,日志將立即被拋棄不再經過其他過濾器;返回NEUTRAL,有序列表里的下個過濾器過接著處理日志;返回ACCEPT,日志會被立即處理,不再經過剩余過濾器。?
過濾器被添加到<Appender>?中,為<Appender>?添加一個或多個過濾器后,可以用任意條件對日志進行過濾。<Appender>?有多個過濾器時,按照配置順序執行。

下面是幾個常用的過濾器:

  • LevelFilter: 級別過濾器,根據日志級別進行過濾。如果日志級別等于配置級別,過濾器會根據onMath 和 onMismatch接收或拒絕日志。有以下子節點:?
    <level>:設置過濾級別?
    <onMatch>:用于配置符合過濾條件的操作?
    <onMismatch>:用于配置不符合過濾條件的操作
  • ThresholdFilter: 臨界值過濾器,過濾掉低于指定臨界值的日志。當日志級別等于或高于臨界值時,過濾器返回NEUTRAL;當日志級別低于臨界值時,日志會被拒絕。?
    例如:過濾掉所有低于INFO級別的日志。
  • EvaluatorFilter: 求值過濾器,評估、鑒別日志是否符合指定條件。有一下子節點:?
    <evaluator>:?
    鑒別器,常用的鑒別器是JaninoEventEvaluato,也是默認的鑒別器,它以任意的Java布爾值表達式作為求值條件,求值條件在配置文件解釋過成功被動態編譯,布爾值表達式返回true就表示符合過濾條件。evaluator有個子標簽<expression>,用于配置求值條件。?
    求值表達式作用于當前日志,logback向求值表達式暴露日志的各種字段:
NameTypeDescription
eventLoggingEvent與記錄請求相關聯的原始記錄事件,下面所有變量都來自event,例如,event.getMessage()返回下面”message”相同的字符串
messageString日志的原始消息,例如,設有logger mylogger,”name”的值是”AUB”,對于 mylogger.info(“Hello {}”,name); “Hello {}”就是原始消息。
formatedMessageString日志被各式話的消息,例如,設有logger mylogger,”name”的值是”AUB”,對于 mylogger.info(“Hello {}”,name); “Hello Aub”就是格式化后的消息。
loggerStringlogger 名。
loggerContextLoggerContextVO日志所屬的logger上下文。
levelint級別對應的整數值,所以 level > INFO 是正確的表達式。
timeStamplong創建日志的時間戳。
markerMarker與日志請求相關聯的Marker對象,注意“Marker”有可能為null,所以你要確保它不能是null。
mdcMap包含創建日志期間的MDC所有值得map。訪問方法是:mdc.get(“myKey”) 。mdc.get()返回的是Object不是String,要想調用String的方法就要強轉,例如,((String) mdc.get(“k”)).contains(“val”) .MDC可能為null,調用時注意。
throwablejava.lang.Throwable如果沒有異常與日志關聯”throwable” 變量為 null. 不幸的是, “throwable” 不能被序列化。在遠程系統上永遠為null,對于與位置無關的表達式請使用下面的變量throwableProxy
throwableProxyIThrowableProxy與日志事件關聯的異常代理。如果沒有異常與日志事件關聯,則變量”throwableProxy” 為 null. 當異常被關聯到日志事件時,”throwableProxy” 在遠程系統上不會為null

<onMatch>:用于配置符合過濾條件的操作?
<onMismatch>:用于配置不符合過濾條件的操作?
例如:過濾掉所有日志消息中不包含“billing”字符串的日志。

轉載于:https://my.oschina.net/huhaoren/blog/1588848

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/539861.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/539861.shtml
英文地址,請注明出處:http://en.pswp.cn/news/539861.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

count(*),count(1),count(0)效率

網上文章很多&#xff0c;今天分別跑了一張2000多萬行的表&#xff0c;該表沒有主鍵&#xff0c;索引&#xff0c;約束條件。 結果是&#xff0c;效率差不多

android 轉場動畫兼容問題,【Android】關于ARouter轉場動畫的問題

實現從主頁跳轉到搜索頁&#xff0c;再從搜索頁回退主頁withTransition(int resId,int resId)這個方法兩個參數第一個的意思是&#xff0c; A 到 B&#xff0c; B 的入場動畫第二個的意思是&#xff0c;A 到 B&#xff0c; A 的出場動畫即&#xff0c;入場動畫&#xff0c;出場…

Oracle 一些常用函數

ROUND&#xff1a; 如何使用 Oracle Round 函數 (四舍五入) 描述 : 傳回一個數值&#xff0c;該數值是按照指定的小數位元數進行四舍五入運算的結果。 SELECT ROUND( number, [ decimal_places ] ) FROM DUAL 參數: number : 欲處理之數值 decimal_places : 四舍五入 , 小數取…

基于github和hexo搭建博客 本地hexo博客搭建

正常都應該講一講為什么搭建博客&#xff0c;不過既然您能看見這篇文章&#xff0c;就說明你想搭建一個自己的博客&#xff0c;無論自己記錄自己的東西&#xff0c;或是為了顯得高大上。那就不廢話了&#xff0c;進入正題。 其實教大家搭建博客的文章很多&#xff0c;講的都不錯…

react不同環境不同配置angular_叫雨山斗雞優勢在哪里,環境不同,價值不同

叫雨山斗雞優勢在哪里&#xff0c;環境不同&#xff0c;價值不同 原生態高端食材網站&#xff0c;專注金線蓮、散放斗雞、斗雞蛋、野生蜂蜜、小耳黑豬肉等云南原生態套餐定制的高端食材供應商。云南叫雨山斗雞叫雨山斗雞原生態飼養 叫雨山斗雞源自于魯西斗雞&#xff0c;初代斗…

android studio 布局拖拽,為什么使用android studio不能像老師一樣在Design里隨意拖動控件...

qq_噴泉_02017-07-25 13:08已采納xmlns:app"http://schemas.android.com/apk/res-auto"xmlns:tools"http://schemas.android.com/tools"android:layout_width"match_parent"android:layout_height"match_parent"tools:context"co…

Oracle自定義函數(不斷更新)

1、將數字轉為ip地址&#xff1a;IPAdd_DotNumFormat create or replace FUNCTION IPAdd_DotNumFormat(v_LfValue number)return varchar2 asv_DotNumString varchar2(50);v_flg Integer;v_NewLfValue number;v_tmp Integer;v_P1 Integer;v_P2 Integer;v_P3 Integer;v_P4…

element ui select設置不顯示不存在的項_appium—等待時間設置方法

引言&#xff1a;在做UI自動化的過程中&#xff0c;我們有時候為了等待元素的出現&#xff0c;需要加一些等待時間來幫助&#xff0c;但是有時候時間加的過多或者過少&#xff0c;這個沒有辦法判斷&#xff0c;今天就介紹幾種等待時間&#xff0c;我們看看那種適合我們 一、強制…

android rn 和webview,RN Webview與Web的通信與調試

React Native Version:0.51RN 在 0.37 版本中加入了WebView功能&#xff0c;所以想要在使用WebView,版本必須>0.37&#xff0c;發送的 message 只能是字符串&#xff0c;所以需要將其他格式的數據轉換成字符串&#xff0c;在接收到后再轉換回去&#xff0c;其實直接用JSON.s…

數據庫完整性檢查

為了主動發現數據庫側頁損壞&#xff0c;保證數據庫邏輯和物理完整性&#xff0c;計劃每周六上午6點&#xff0c;針對生產主庫上的所有系統和用戶數據庫執行DBCC CHECKDB&#xff0c;將結果記錄到表中。以下為理論依據&#xff1a;SQL Server數據庫可以檢測出頁損壞&#xff0c…

GNU概念

一、GNU的意思 GNU的全稱&#xff1a;GNU is not unix&#xff0c;意思是&#xff1a;GNU 不是 unix 問&#xff1a;為什么這樣取名&#xff1f; 答&#xff1a;為了打造一個不是unix又類unix的系統 二、GNU的歷程 GNU計劃是由Richard Stallman 在1984年公開發起的&#x…

Item 13 Minimize the accessibility of classes and members

區分好的模塊和不好的模塊最重要的因素是看這個模塊對于其他模塊而言是否隱藏內部數據和其他細節。好的模塊會把所有細節隱藏起來&#xff0c;把API和實現隔離開來&#xff0c;模塊之間用API通信。這就是information hiding或者封裝(encapsulation)。是軟件設計基本原則之一。 …

html 物流狀態,使用css實現物流進度的樣式的實例代碼

效果&#xff1a;css樣式&#xff1a;ul li {list-style: none;}.package-status {padding: 18px 0 0 0}.package-status .status-list {margin: 0;padding: 0;margin-top: -5px;padding-left: 8px;list-style: none;}.package-status .status-list>li {border-left: 2px so…

GPL概念

一、GPL概念 全稱為 General Public License&#xff0c;翻譯為通用公共許可&#xff0c;是最著名的開源許可協議。Linux內核就是在GPL許可下發布的&#xff0c;GPL許可是由自由軟件基金會Free Software foundation 創建的&#xff0c;由Richard Stallman 和一幫人共同努力發起…

點鈔機語音怎么打開_原來微信語音一樣能轉發? 居然還有人不知道

微信怎么把語音轉發給別人&#xff1f;原來這個簡單啊&#xff0c;微信作為一款我們最常用的社交工具&#xff0c;無論是生活還是工作過程中&#xff0c;我們都能夠用到微信。那么大家知道微信怎么把語音轉發給別人嗎&#xff1f;有的人肯定就會回答說&#xff1a;"跟轉發…

圓與平面的接觸面積_視頻:5.3RJ六年級上冊圓的面積例題+習題講解

一、什么是面積物體表面的大小就是它們的面積。長方形的面積長寬正方形的面積邊長邊長平行四邊形的面積底高三角形的面積底高2梯形的面積(上底下底)高2圓所占平面的大小叫做圓的面積。二、剪切法推導圓的面積把圓轉化成近似的長方形&#xff0c;當平均分成的份數越來越多&#…

Reactjs 踏坑指南1: 一些概念

Reactjs 踏坑指南1&#xff1a; 知識點 什么是React虛擬DOMJSX組件生命周期和狀態事件單項數據流Reactjs和Angularjs的對比React簡介 React是一個Facebook開發的UI庫。使用這個庫可以很方便的開發交互式的、具有表達力的和可重用的UI組件。本身并不是一個框架&#xff0c;可視為…

Linux為什么受歡迎?

1、Linux以高效和靈活著稱&#xff0c;實現了幾乎全部的Unix特性&#xff0c;同時具備多任務&#xff0c;多用戶的能力&#xff0c;支持多線程&#xff0c;多CPU架構。 2、Linux操作系統軟件包&#xff1a;包含了文本編輯器&#xff0c;高級語言編譯器&#xff0c;以及X-Windo…

直播的學習與使用-----采集

// 捕獲音視頻 - (void)setupCaputureVideo { // 1.創建捕獲會話,必須要強引用&#xff0c;否則會被釋放 AVCaptureSession *captureSession [[AVCaptureSession alloc] init]; _captureSession captureSession; // 2.獲取攝像頭設備&#xff0c;默認是后置攝像頭 AVCaptureD…