log4j配置_是时候了解一下log4j2各种配置的含义了!
来源:http://i7q.cn/54K3Uw
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.slf4jgroupId> <artifactId>slf4j-apiartifactId> <version>1.7.25version>dependency><dependency> <groupId>org.apache.logging.log4jgroupId> <artifactId>log4j-slf4j-implartifactId> <version>2.11.0version>dependency><dependency> <groupId>org.apache.logging.log4jgroupId> <artifactId>log4j-coreartifactId> <version>2.11.0version>dependency><dependency> <groupId>org.apache.logging.log4jgroupId> <artifactId>log4j-apiartifactId> <version>2.11.0version>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配置文件的理解
配置文件结构:
Appdenders
部分Appender
Filter
Layout
Policies
Strategy
Appender
Loggers
部分Logger
RootLogger
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>
<Root level="info">
<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>
<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.lopapp.3.lop -> app.2.lop...app.10.lop -> app.9.lopapp.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">
<Filters>
<LevelRangeFilter minLevel="error" maxLevel="info" onMatch="ACCEPT" onMismatch="NEUTRAL" />
<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, 看父类的实现类有哪些。
简单示例:
"%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>
<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%nPattern> 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%nPattern> 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>
<Root level="info">
<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>
<logger name="org.springframework" level="INFO"/>
<Root level="info"> <AppenderRef ref="File"/> Root>
Loggers>
Configuration>
技术交流群
log4j配置_是时候了解一下log4j2各种配置的含义了!相关推荐
- 华为交换机ipv6默认路由配置_静态路由和默认路由的配置
一.静态路由的配置 下边实验对该拓扑图进行配置 实验目标:配置静态路由,实现全网互通 1.配置路由器R1 进入接口f0/0,配置IP,并开启. 进入接口f0/1,配置IP,并开启. 设置静态路由. c ...
- ssm 返回json配置_摆脱困境:将运行时配置作为JSON返回
ssm 返回json配置 如果需要确定部署到远程服务器的Spring Web应用程序的运行时配置,则需要读取从远程服务器找到的属性文件. 这很麻烦. 幸运的是,有更好的方法. 这篇博客文章描述了我们如 ...
- jboss as安装配置_书评:JBoss AS 7:配置,部署和管理
jboss as安装配置 我热切地接受Packt Publishing邀请复审JBoss AS 7:配置,部署和管理,因为自从我上次使用JBoss已有数年了,我很想了解有关JBoss AS 7的更多信 ...
- 交华为换机access配置_华为交换机Hybrid接口及基础配置
一.回顾VLAN VLAN基本概念 VLAN即虚拟局域网,是将一个物理的LAN在逻辑上划分成多个广播域(多个VLAN)的通信技术.VLAN内的主机间可以直接通信,而VLAN间不能直接互通,从而将广播报 ...
- java 连接池配置_【Java】java数据库连接池配置的几种方法
今天遇到了关于数据源连接池配置的问题,发现有很多种方式可以配置,现总结如下,希望对大家有所帮助:(已Mysql数据库为例) 一,Tomcat配置数据源: 方式一:在WebRoot下面建文件夹META- ...
- ac6005直连ap 如何配置_【无线】无线瘦AP配置如何进行AC直连AP配置
适用场景说明 当无线网络中的AP数量众多,而且需要统一管理和配置. 优点:通过AC(AP控制器)统一配置和管理AP.包括配置下发.升级.重启等 缺点:需要增加网络设备AC,增加有线网络的配置,不同厂商 ...
- centos ip配置_在虚拟机(Vmware)中配置centos7系统静态ip,就是如此简单
1 背景 使用vmware或virtualbox安装了centos操作系统后,下一步要做的要做的就是设置网络.通常linux系统是用来做服务器的,也很少使用(安装)桌面版的系统.服务器通常是放在服务运 ...
- feignclient多个配置_@FeignClient同一个name使用多个配置类的解决方案
Feign有一个局限性,即对于同一个service-id只能使用一个配置类,如果有多个@FeignClient注解使用了相同的name属性,则注解的configuration参数会被覆盖.至于谁覆盖谁 ...
- sw标准件不能配置_思科设备与华为设备在配置Telnet,有啥不一样呢?
在工作中,可能我们会遇到思科的设备或者华为的,所以,我们需要不断的补充自己的知识,慢慢从小白走向大神之路.今天来看看思科与华为设备在配置Telnet有啥不一样的 思科路由器2901配置Telnet远程 ...
最新文章
- websocket+netty实时视频弹幕交互功能(Java版)
- [C++] 指向常量的指针 VS 指针类型的常量
- python基础教程书籍推荐-初学者python入门必看书籍推荐(上)
- 问题描述 给定一个由n行数字组成的数字三角形如下图所示。试设计一个算法,计算出从三角形的顶至底的一条路径,使该路径经过的数字总和最大。 对于给定的由n行数字组成的数字三角形,计算从三角形的顶至底
- Silverlight在IIS中的配置
- Points角点halcon算子,持续更新
- C语言编程快速入门黎明,何用C语言模拟键盘输入?
- 人间不值得?250000条数据分析李诞是不是被骂火的
- 织梦生成的html路径,织梦dedecms安装在子目录网页生成在根目录如何设置
- AI 算法在 FPGA 芯片上还有这种操作?
- 如何搭建测试平台?理清思路很重要
- 阿里架构师:​程序员必须掌握的几项核心能力
- 对HTML5标签的认识(三)
- 只做正确的事情,并持续输出价值
- html图片原始比例_html图片如何按屏幕大小等比例缩放?
- matlab中floor函数,floor函数
- 2_Gui_Tkinter(python标准库)
- 4.4 给单元格快速添加斜线 [原创Excel教程]
- bzoj4444: [Scoi2015]国旗计划(线段树+倍增)
- html a标签发微信,a标签的特殊和文本的样式
热门文章
- 文献学习(part23)--双向聚类方法综述
- 机器学习中的不平衡分类方法(part4)--朴素贝叶斯分类器
- android 图片气泡,android图片上显示气泡消息
- SAP Spartacus UI Duplicated keys has been found in the config of i18n chunks
- 如何让 Visual Studio Code 里显示 Cypress 的 intelligent code suggestion
- Rxjs debounce 操作符在 SAP Spartacus 函数节流中的一个实际使用例子
- 什么是 SAP UI5 的 Component-preload.js, 什么是Minification和Ugification
- 试图用Session Administration删除某用户的session时报错
- SAP HANA CLOUD和aws一个实际项目中的性能比较
- SAP ABAP SICF事务码和SAP Hybris的链式过滤器filter chain