1. 配置文件的基本结构

1.1. Logback配置文件的语法非常灵活。正因为灵活, 所以无法用DTD或XML schema进行定义。尽管如此, 可以这样描述配置文件的基本结构: 以<configuration>开头, 后面有零个或多个<appender>元素, 有零个或多个<logger>元素, 有最多一个<root>元素。

2. 配置logger或<logger>元素

2.1. Logger是用<logger>元素配置的。<logger>元素有且仅有一个name属性、一个可选的level属性和一个可选的additivity属性。Level属性的值大小写无关, 其值为: TRACE、DEBUG、INFO、 WARN、ERROR、ALL和OFF中的一个值。还可以是一个特殊的字符串"INHERITED"或其同义词"NULL", 表示强制继承上级的级别。

2.2. <logger>元素可以包含零个或多个<appender-ref>元素, 表示这个appender会被添加到该logger。强调一下, 每个用<logger>元素声明的logger, 首先会移除所有的appender, 然后添加引用的appender, 所以如果logger没有引用任何appender, 就会失去所有appender。

2.3. 例子

2.3.1. 新建一个名为LogbackCfgGrammer的Java项目, 同时添加相关jar包

2.3.2. 编辑LoggerCfg.java

package com.zr.cfg;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;public class LoggerCfg {private static final Logger logger = LoggerFactory.getLogger(LoggerCfg.class);public static void main(String[] args) {// 上下文LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();// Joran配置文件处理类JoranConfigurator cfg = new JoranConfigurator();cfg.setContext(lc);// 上下文已经读取配置文件或使用默认配置文件, 这里进行重置操作。lc.reset();try {cfg.doConfigure("cfg/logger.xml");} catch (JoranException e) {e.printStackTrace();}logger.info("配置logger或<logger>元素");logger.debug("配置logger或<logger>元素");}
}

2.3.3. 新建cfg文件夹, 在该文件夹下编辑logger.xml

<configuration><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">  <encoder charset="UTF-8">  <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>  </encoder>  </appender> <logger name="com.zr.cfg.LoggerCfg" level="info"><appender-ref ref="stdout" /></logger></configuration>

2.3.4. 只会打印info和高于info级别的日志

3. 配置根logger或<root>元素

3.1. <root>元素配置根logger。该元素有一个level属性。没有name属性, 因为已经被命名为"ROOT"。Level属性的值大小写无关, 其值为: TRACE、DEBUG、INFO、 WARN、ERROR、ALL和OFF中的一个值。注意不能设置为"INHERITED"或"NULL"。

3.2. <logger>元素可以包含零个或多个<appender-ref>元素。与<logger>元素类似, 声明<root>元素后, 会先关闭然后移除全部当前appender, 只引用声明的appender。如果root元素没有引用任何appender, 就会失去所有appender。

3.3. 基本选择规则依赖于被调用的logger的有效级别, 而不是appender所关联的logger的级别。Logback首先判断记录语句是否被启用, 如果启用, 则调用logger等级里的appender, 同时如果有继承的话, 还会调用祖先的appender, 无视logger的级别。

3.4. 例子

3.4.1. 编辑RootLoggerCfg.java

package com.zr.cfg;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;public class RootLoggerCfg {private static final Logger logger = LoggerFactory.getLogger(RootLoggerCfg.class);public static void main(String[] args) {// 上下文LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();// Joran配置文件处理类JoranConfigurator cfg = new JoranConfigurator();cfg.setContext(lc);// 上下文已经读取配置文件或使用默认配置文件, 这里进行重置操作。lc.reset();try {cfg.doConfigure("cfg/rootlogger.xml");} catch (JoranException e) {e.printStackTrace();}logger.info("配置根logger或<root>元素");logger.debug("配置根logger或<root>元素");}
}

3.4.2. 在cfg文件夹下编辑rootlogger.xml

<configuration><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">  <encoder charset="UTF-8">  <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>  </encoder>  </appender> <logger name="com.zr.cfg.RootLoggerCfg" level="info"></logger><root level="off"><appender-ref ref="stdout" /></root>
</configuration>

3.4.3. 各个logger的级别

3.4.4. 配置里唯一的appender"stdout", 被关联到级别为OFF的根logger, 根logger的级别不起任何作用。com.zr.cfg.RootLoggerCfg类的INFO级别是启用的, 因此会输出com.zr.cfg.RootLoggerCfg类INFO级别及其更高级别的日志:

4. 配置Appender

4.1. Appender用<appender>元素配置, 该元素必要属性name和class。name属性指定appender的名称, class属性指定appender类的全限定名。

4.2. <appender>元素可以包含零个或一个<layout>元素或者零个或一个<encoder>元素和零个或多个<filter>元素。除了这三个常用元素之外, 还可以包含任意数量的javabean属性。

4.3. 下图演示了常用结构, 注意对javabean属性的支持在图中不可见。

4.4. <layout>元素的class属性是必要的, 表示将被实例化的layout类的全限定名。因为太常用了, 所以当layout是PatternLayout 时, 可以省略class属性。

4.5. <encoder>元素class属性是必要的, 表示将被实例化的encoder类的全限定名。因为太常用了, 所以当encoder是PatternLayoutEncoder时, 可以省略class属性。

4.6. 记录输出到多个appender很简单, 先定义各种appender, 然后在logger里进行引用就行了。

4.7. 注意每个appender都有自己的encoder。Encoder通常不能被多个appender共享, layout也是。

4.8. 例子

4.8.1. 编辑AppenderCfg.java

package com.zr.cfg;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;public class AppenderCfg {private static final Logger logger = LoggerFactory.getLogger(AppenderCfg.class);public static void main(String[] args) {// 上下文LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();// Joran配置文件处理类JoranConfigurator cfg = new JoranConfigurator();cfg.setContext(lc);// 上下文已经读取配置文件或使用默认配置文件, 这里进行重置操作。lc.reset();try {cfg.doConfigure("cfg/appender.xml");} catch (JoranException e) {e.printStackTrace();}logger.info("Appender用<appender>元素配置, 该元素必要属性name和class。");logger.debug("name属性指定appender的名称, class属性指定appender类的全限定名。");}
}

4.8.2. 在cfg文件夹下编辑appender.xml

<configuration><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"><layout class="ch.qos.logback.classic.PatternLayout"><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></layout></appender><appender name="file" class="ch.qos.logback.core.FileAppender"><file>log/my.log</file><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><root level="debug"><appender-ref ref="file" /><appender-ref ref="stdout" /></root></configuration>

4.8.3. 运行结果

4.9. Appender累积

4.9.1. 默认情况下, appender是可累积的: logger会把记录输出到它自身的appender和它所有祖先的appender。因此, 把同一appender关联到多个logger会导致重复输出。

4.9.2. Appender的叠加性对新手来说并不是陷阱, 反而是非常方便的。举例来说, 你可以让某些系统里所有logger的记录信息出现在控制台, 却让某些特定logger的记录信息发到一个特定的appender。

<configuration><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"><layout class="ch.qos.logback.classic.PatternLayout"><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></layout></appender><appender name="file" class="ch.qos.logback.core.FileAppender"><file>log/error.log</file><append>false</append><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><logger name="com.zr.cfg.AccumulateCfg" level="error"><appender-ref ref="file" /></logger><root><appender-ref ref="stdout" /></root></configuration>

4.9.3. 如果你觉得默认的累积行为不合适, 可以设置叠加性标识为false以关闭它。这样的话, logger树里的某个分支可以输出到与其他logger不同的appender。

<configuration><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"><layout class="ch.qos.logback.classic.PatternLayout"><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></layout></appender><appender name="file" class="ch.qos.logback.core.FileAppender"><file>log/error.log</file><append>false</append><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><logger name="com.zr.cfg.AccumulateCfg" level="error" additivity="false"><appender-ref ref="file" /></logger><root><appender-ref ref="stdout" /></root></configuration>

4.9.4. 创建AccumulateCfg.java

package com.zr.cfg;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;public class AccumulateCfg {private static final Logger logger = LoggerFactory.getLogger(AccumulateCfg.class);private static final Logger root = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);public static void main(String[] args) {// 上下文LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();// Joran配置文件处理类JoranConfigurator cfg = new JoranConfigurator();cfg.setContext(lc);// 上下文已经读取配置文件或使用默认配置文件, 这里进行重置操作。lc.reset();try {cfg.doConfigure("cfg/accumulate.xml");} catch (JoranException e) {e.printStackTrace();}logger.error("默认情况下, appender是可累积的: logger会把记录输出到它自身的appender和它所有祖先的appender。");logger.error("因此, 把同一appender关联到多个logger会导致重复输出。");logger.error("Appender的叠加性对新手来说并不是陷阱, 反而是非常方便的。");root.warn("举例来说, 你可以让某些系统里所有logger的记录信息出现在控制台, 却让某些特定logger的记录信息发到一个特定的appender。");root.info("如果你觉得默认的累积行为不合适, 可以设置叠加性标识为false以关闭它。");root.debug("这样的话, logger树里的某个分支可以输出到与其他logger不同的appender。");}
}

4.9.5. 创建accumulate.xml, 使用步骤4.9.2.的配置文件

4.9.6. 运行AccumulateCfg.java

4.9.7. 修改accumulate.xml配置, 使用步骤4.9.3.的配置文件, 再次运行AccumulateCfg.java

5. 设置上下文名称

5.1. 每个logger都关联到logger上下文。默认情况下, logger上下文名为"default"。但是你可以借助配置指令<contextName>设置成其他名字。注意一旦设置logger上下文名称后, 不能再改。设置上下文名称后, 可以方便地区分来自不同应用程序的记录。

5.2. 例子

5.2.1. 编辑ContextName.java

package com.zr.cfg;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;public class ContextName {private static final Logger logger = LoggerFactory.getLogger(ContextName.class);public static void main(String[] args) {// 上下文LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();// Joran配置文件处理类JoranConfigurator cfg = new JoranConfigurator();cfg.setContext(lc);// 上下文已经读取配置文件或使用默认配置文件, 这里进行重置操作。lc.reset();try {cfg.doConfigure("cfg/contextName.xml");} catch (JoranException e) {e.printStackTrace();}logger.info("每个logger都关联到logger上下文。");logger.debug("你可以借助配置指令<contextName>设置上下文名字。");}
}

5.2.2. 在cfg文件夹下编辑contextName.xml

<configuration debug="true"><contextName>日志服务器</contextName><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">  <encoder charset="UTF-8">  <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>  </encoder>  </appender> <root><appender-ref ref="stdout" /></root>
</configuration>

5.2.3. 运行结果

6. 变量替换

6.1. 原则上, 指定变量的地方就能够发生变量替换。变量替换的语法与Unix shell中的变量替换相似。位于"${"与"}"之间的字符串是键(key), 取代键的值可以在同一配置文件里指定, 也可以在外部文件或通过系统属性进行指定。

6.2. 属性被插入logger上下文

6.2.1. 注意通过<property>元素定义的值实际上会被插入logger上下文。换句话说, 这些值变成了logger上下文的属性。所以, 它们对所有记录事件都可用, 包括通过序列化方式被发送到远程主机的记录事件。

6.2.2. 下面的例子在配置文件的开头声明了一个变量又名替换属性, 它代表输出文件的位置, 然后在后面的配置文件里使用它。

<property name="fileName" value="my.log" />

6.3. 属性文件

6.3.1. 当需要很多变量时, 更方便的做法是在一个单独的文件里声明所有变量。

<property file="variables.properties" /> 

6.3.2. 还可以不引用文件, 而是引用class path上的资源。

<property resource="variables.properties" />

6.3.3. variables.properties文件内容类似于:

pathPre=/log
fileName=my.log
fullPath=/log/my.log

6.4. 嵌套变量替换

6.4.1. Logback支持嵌套变量替换。这里的嵌套是指变量的值里包含对其他变量的引用。

pathPre=/log
fileName=my.log
fullPath=${pathPre}/${fileName}

6.5. 变量的默认替换值

6.5.1. 在某些特定情况下, 最好给变量一个默认值, 以免变量未被声明或值为null。Bash shell用":-"指定默认值。例如, 假设"appName"未被声明, 那么"${appName:-zrApp}"将被解释为"zrApp"。

6.6. Logback自动定义了一个常用变量"${HOSTNAME}"。

7. 配置文件里的条件化处理

7.1. 开发者经常需要针对不同的环境在不同的配置文件里换来换去, 比如开发、测试和生产环境。这些配置文件大同小异。为避免重复劳动, logback支持在配置文件里进行条件化处理, 用<if>、<then>和<else>这些元素可以让一个配置文件适用于多个环境。

7.2. 条件语句一般格式如下

<configuration> <!-- if-then form -->  <if condition="some conditional expression">   <then>     ...   </then>  </if> <!-- if-then-else form -->  <if condition="some conditional expression">   <then>     ...   </then>   <else>     ...    </else>  </if> </configuration

7.3. 其中"condition"是java表达式, 只允许访问上下文属性和系统属性。对于作为参数传入的键, property()方法或其等价的p()方法将返回属性的字符串值。例如, 想访问属性键为"k"的值, 你可以用property("k")或等价的 p("k")。如果键为"k"的属性未被定义, property方法将返回空字符串而不是null, 这样避免了检查null值。

7.4. 例子

7.4.1. 条件语句需要两个额外的包commons-compiler-3.1.3.jar和janino-3.1.3.jar

7.4.2. 编辑Condition.java

package com.zr.cfg;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;public class Condition {private static final Logger logger = LoggerFactory.getLogger(Condition.class);public static void main(String[] args) {// 上下文LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();// Joran配置文件处理类JoranConfigurator cfg = new JoranConfigurator();cfg.setContext(lc);// 上下文已经读取配置文件或使用默认配置文件, 这里进行重置操作。lc.reset();try {cfg.doConfigure("cfg/condition.xml");} catch (JoranException e) {e.printStackTrace();}logger.error("错误信息");logger.warn("警告信息");logger.info("信息");logger.debug("测试信息");}
}

7.4.3. 在cfg文件夹下编辑condition.xml

<configuration><property name="development" value="dev" /><contextName>${pathPre:-zrApp}</contextName><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">  <encoder charset="UTF-8">  <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>  </encoder>  </appender> <if condition='p("development").contains("test")'> <then> <root level="debug"><appender-ref ref="stdout" /></root></then><else>  <root level="warn"><appender-ref ref="stdout" /></root></else></if>
</configuration>

7.4.4. 运行结果

8. 从JNDI获取变量

8.1. 在某些特定情况下, 你也许利用JNDI里存储的env项, <insertFromJNDI>指令会从JNDI里取得env项, 然后用as属性把它们作为变量。

8.2. 新建一个名为JNDIGetVariable的动态Web工程, 同时添加相关jar包

8.3. 创建JNDIAction.java

package com.fj;import java.io.IOException;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class JNDIAction extends HttpServlet {private static final long serialVersionUID = 1L;private static final Logger logger = LoggerFactory.getLogger(JNDIAction.class);@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {try {InitialContext ctx = new InitialContext();String contextName = (String) ctx.lookup("java:comp/env/logback/context-name");logger.error("从JNDI获取变量: {}", contextName);} catch (NamingException e) {e.printStackTrace();}}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}
}

8.4. 在src目录下添加logback.xml

<configuration><insertFromJNDI env-entry-name="java:comp/env/logback/context-name" as="context-name" /><contextName>${context-name}</contextName><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>%contextName %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><root level="debug"><appender-ref ref="stdout" /></root></configuration>

8.5. 配置web.xml

8.6. 运行项目

9. 文件包含

9.1. Joran支持在配置文件里包含其他文件。方法是声明<include>元素, 被包含的内容可以是文件、资源或URL。

9.2. 作为文件, 用"file"属性包含一个文件。可以用相对路径, 但是需要注意, 当前目录是由应用程序决定的, 与配置文件的路径必要的联系。

<include file="includedConfig.xml" /> 

9.3. 作为资源, 用"resource"属性包含一个资源, 也就是在class path上的文件。

<include resource="includedConfig.xml" />

9.4. 作为URL, 用"url"属性包括一个URL。

<include url="http://some.host.com/includedConfig.xml" /> 

9.5. 被包含的文件必须把它的元素嵌套在<included>元素里。请注意<included>元素是必需的。

9.6. 例子

9.6.1. 编辑IncludeCfg.java

package com.zr.cfg;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;public class IncludeCfg {private static final Logger logger = LoggerFactory.getLogger(IncludeCfg.class);public static void main(String[] args) {// 上下文LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();// Joran配置文件处理类JoranConfigurator cfg = new JoranConfigurator();cfg.setContext(lc);// 上下文已经读取配置文件或使用默认配置文件, 这里进行重置操作。lc.reset();try {cfg.doConfigure("cfg/containingcfg.xml");} catch (JoranException e) {e.printStackTrace();}logger.error("错误信息");logger.warn("警告信息");logger.info("信息");logger.debug("测试信息");}
}

9.6.2. 在cfg文件夹下编辑containingcfg.xml

<included><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">  <encoder charset="UTF-8">  <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>  </encoder>  </appender>
</included>

9.6.3. 在cfg文件夹下编辑includecfg.xml

<configuration><include file="cfg/includecfg.xml"></include><root><appender-ref ref="stdout" /></root>
</configuration>

9.6.4. 运行结果

008_logback配置语法相关推荐

  1. Highcharts 配置语法;Highcharts 配置选项详细说明

    Highcharts 配置语法 本章节我们将为大家介绍使用 Highcharts 生成图表的一些配置. 第一步:创建 HTML 页面 创建一个 HTML 页面,引入 jQuery 和 Highchar ...

  2. Git 中 .gitignore 的配置语法

    一.前言 在日常的开发中,当我们需要将一个项目提交到 Git 时,并不是所有的文件都需要提交,比如一些自动生成的文件,类似于 .idea 文件.class 文件等,这时候就可以使用.gitignore ...

  3. Nginx——nginx作为静态资源web服务(配置语法)

    目录 一.sendfile的配置语法(即文件读取的配置语法) 二.tcp_nopush的配置语法(即高传输效率的配置语法) 三.tcp_nodelay的配置语法(即实时性的配置语法) 四.gzip的配 ...

  4. 【转】Vczh Library++3.0之可配置语法分析器(前言)

    从网上无意间看到这个系列的文章,作者非常有想法,转下来慢慢研究,好好学习. 祝大家学习愉快,做自己的爱好 ^_^ ! 花了差不多两个星期的时间将一个可配置语法分析器(Combinator)写好了.这个 ...

  5. C++轻量级可配置语法分析器(开源) - λ-calculus(惊愕到手了欧耶,GetBlogPostIds.aspx) - C++博客...

    C++轻量级可配置语法分析器(开源) - λ-calculus(惊愕到手了欧耶,GetBlogPostIds.aspx) - C++博客 C++轻量级可配置语法分析器(开源) - λ-calculus ...

  6. syslog-ng详解——syslog-ng配置语法

    在"运行syslog-ng"中我们简单介绍了一个基本配置文件的大概结构,保证syslog-ng能正常运行起来.这边将详细介绍下syslog-ng的日志配置及如何进行高效的配置,先介 ...

  7. 重识Nginx - 03 Nginx配置语法

    文章目录 Nginx配置语法 配置参数: 时间的单位 配置参数: 空间的单位 http配置的指令块 Nginx配置语法 配置文件由指令与指令块构成 每条指令以;分号结尾,指令与参数间以空格符号分隔 指 ...

  8. 【转】Vczh Library++ 3.0之可配置语法分析器(设计文法表达式)

    从网上无意间看到这个系列的文章,作者非常有想法,转下来慢慢研究,好好学习. 祝大家学习愉快,做自己的爱好 ^_^ ! 上一篇文章中我们看到了可配置语法分析器使用起来的样子,在这篇文章中我将告诉大家如何 ...

  9. linux下varnish4配置语法(基础)

    varnish4 安装可以查看:http://php2012web.blog.51cto.com/5585213/1640182 VCL 说明文档:https://www.varnish-cache. ...

最新文章

  1. datatable如何生成级联数据_UE4 C++结合DataTable批量快速创建DataAsset
  2. 计算机控制水槽液位控制,计算机过程控制实验报告单容水箱液位数学模型的测定实验...
  3. 操作系统及编程语言历史以及shell命令
  4. 标签插入两一个html,一个类下有很多a标签,给第二个a标签添加样式,怎么写才能不用再给第二个a添加类_html/css_WEB-ITnose...
  5. 谷歌AI掌门人Jeff Dean获冯诺依曼奖;微软计划自研PC和服务器芯片;Ruby 3.0 RC1发布|极客头条...
  6. python安装csv出错_python处理csv文件问题解决贴
  7. mysql数据库在linux下的导出和导入及每天的备份
  8. 昂达v891w可以用u盘linux,拆机小能手——ONDA 昂达 V891w CH 双系统电脑国产平板 拆解清灰!...
  9. box-sizing: border-box的作用
  10. 京东商品如何批量修改?
  11. python代码画人物_Python绘制可爱的卡通人物 | 【turtle使用】
  12. 北京住房公积金联名卡查询使用
  13. 计算机购销存系统论文,企业进销存管理系统毕业论文.doc
  14. 缓解环境噪声对音频质量干扰
  15. 腾讯微服务框架 Tars 的 Go 性能提升之路
  16. Android开发——集成友盟社会化分享遇到的坑(一)
  17. 阿里云OSS服务使用操作流程
  18. java实现二维码生成的几个方法
  19. 简述计算机辅助船舶制造的技术特点,01234计算机辅助船舶制造.doc
  20. 强制加班下的员工状态

热门文章

  1. Yii2中如何将Jquery放在head中的方法
  2. ExtJS的xtype列表
  3. sharepoint站点Feature的定制与开发 以及 stsadm 常用命令
  4. Linux 知识点滴
  5. 信息技术专业常用协议指什么?
  6. windows下编译jsoncpp 1.y.z
  7. MySQL导入导出命令
  8. 《流畅的python》第四章 文本和字节序列
  9. P4127 [AHOI2009]同类分布
  10. 2.redis配置详解