看过我前面几个帖子的伙伴也许知道, logback会自动加载配置文件
那为毛,官方还会提供spring
ch.qos.logback.ext.spring.web.LogbackConfigListener 呢?
参见
maven 引用
<dependency>
<groupId>org.logback-extensions</groupId>
<artifactId>logback-ext-spring</artifactId>
<version>0.1.2</version>
<scope>compile</scope>
</dependency>
此外,号外下 LogbackConfigListener 和spring-web-${version}.jar 里面的org.springframework.web.util.Log4jConfigListener 的作者是同一个人 : Juergen Hoeller
大家对于spring 可能只知道spring 之父 Rod Johnson,而Juergen Hoeller 也是牛人,Juergen Hoeller是Spring框架的联合创始人,自2003年2月Rod的Interface21将Spring框架开源起,他就是最活跃的Spring开发者。Juergen是一名经验丰富的咨询师,擅长于Web应用、事务管理、O/R映射技术以及轻量级远程调用。
大家有兴趣的话,可以在这里看到他的专访
http://www.infoq.com/cn/interviews/hoeller-spring31-32-cn
spring4是他主导的
https://spring.io/team/jhoeller
好吧,我们回到正题, "为毛官方还会提供spring ch.qos.logback.ext.spring.web.LogbackConfigListener 呢?"
在这里我们可以找到说明
https://github.com/qos-ch/logback-extensions/wiki/Spring
官方给出了两点理由:
- 通过
web.xml
ServletContextListener or Servlet for Spring-based web applications初始化 Intialize Logback . - 使用 Spring configuration (e.g.
applicationContext.xml
and Spring Java config) 配置Logback components (Appenders, Layouts, 等) .
注意: ch.qos.logback.ext.spring.web.LogbackConfigListener 需要 spring 3.1.1+版本
看了下usage 感觉没有什么用
比如 ,可以在spring applicationContext.xml bean 里面 配置 相关的 logback appender
<beans ...>
...
<bean id="consoleAppender" class="ch.qos.logback.core.ConsoleAppender" init-method="start" destroy-method="stop">
<property name="context" value="#{ T(org.slf4j.LoggerFactory).getILoggerFactory() }"/>
<property name="encoder">
<bean class="ch.qos.logback.classic.encoder.PatternLayoutEncoder" init-method="start" destroy-method="stop">
<property name="context" value="#{ T(org.slf4j.LoggerFactory).getILoggerFactory() }"/>
<property name="pattern" value="%date %-5level [%thread] %logger{36} %m%n"/>
</bean>
</property>
</bean>
...
</beans>
不过 usage 实用的(适合我用的)没什么, 但是我们还是追追源码,瞅瞅有啥好玩的
public class LogbackConfigListener implements ServletContextListener {
@Override
public void contextDestroyed(ServletContextEvent event) {
WebLogbackConfigurer.shutdownLogging(event.getServletContext());
}
@Override
public void contextInitialized(ServletContextEvent event) {
WebLogbackConfigurer.initLogging(event.getServletContext());
}
}
ch.qos.logback.ext.spring.web.LogbackConfigListener 就是个普通的 ServletContextListener
核心代码 ,调用的 ch.qos.logback.ext.spring.web.WebLogbackConfigurer.initLogging(ServletContext)
public static void initLogging(ServletContext servletContext) {
// Expose the web app root system property.
if (exposeWebAppRoot(servletContext)) {
WebUtils.setWebAppRootSystemProperty(servletContext);
}
// Only perform custom Logback initialization in case of a config file.
String location = servletContext.getInitParameter(CONFIG_LOCATION_PARAM);
if (location != null) {
// Perform actual Logback initialization; else rely on Logback's default initialization.
try {
// Resolve system property placeholders before potentially resolving real path.
location = SystemPropertyUtils.resolvePlaceholders(location);
// Return a URL (e.g. "classpath:" or "file:") as-is;
// consider a plain file path as relative to the web application root directory.
if (!ResourceUtils.isUrl(location)) {
location = WebUtils.getRealPath(servletContext, location);
}
// Write log message to server log.
servletContext.log("Initializing Logback from [" + location + "]");
// Initialize
LogbackConfigurer.initLogging(location);
} catch (FileNotFoundException ex) {
throw new IllegalArgumentException("Invalid 'logbackConfigLocation' parameter: " + ex.getMessage());
} catch (JoranException e) {
throw new RuntimeException("Unexpected error while configuring logback", e);
}
}
//If SLF4J's java.util.logging bridge is available in the classpath, install it. This will direct any messages
//from the Java Logging framework into SLF4J. When logging is terminated, the bridge will need to be uninstalled
try {
Class<?> julBridge = ClassUtils.forName("org.slf4j.bridge.SLF4JBridgeHandler", ClassUtils.getDefaultClassLoader());
Method removeHandlers = ReflectionUtils.findMethod(julBridge, "removeHandlersForRootLogger");
if (removeHandlers != null) {
servletContext.log("Removing all previous handlers for JUL to SLF4J bridge");
ReflectionUtils.invokeMethod(removeHandlers, null);
}
Method install = ReflectionUtils.findMethod(julBridge, "install");
if (install != null) {
servletContext.log("Installing JUL to SLF4J bridge");
ReflectionUtils.invokeMethod(install, null);
}
} catch (ClassNotFoundException ignored) {
//Indicates the java.util.logging bridge is not in the classpath. This is not an indication of a problem.
servletContext.log("JUL to SLF4J bridge is not available on the classpath");
}
}
关于WebUtils.setWebAppRootSystemProperty(ServletContext)
我们先来看看
// Expose the web app root system property.
if (exposeWebAppRoot(servletContext)) {
WebUtils.setWebAppRootSystemProperty(servletContext);
}
意思是 如果web.xml配置了
<context-param>
<param-name>logbackExposeWebAppRoot</param-name>
<param-value>true</param-value>
</context-param>
或者没有配置 logbackExposeWebAppRoot
会调用 org.springframework.web.util.WebUtils.setWebAppRootSystemProperty(ServletContext)
public static void setWebAppRootSystemProperty(ServletContext servletContext) throws IllegalStateException {
Assert.notNull(servletContext, "ServletContext must not be null");
String root = servletContext.getRealPath("/");
if (root == null) {
throw new IllegalStateException(
"Cannot set web app root system property when WAR file is not expanded");
}
String param = servletContext.getInitParameter(WEB_APP_ROOT_KEY_PARAM);
String key = (param != null ? param : DEFAULT_WEB_APP_ROOT_KEY);
String oldValue = System.getProperty(key);
if (oldValue != null && !StringUtils.pathEquals(oldValue, root)) {
throw new IllegalStateException(
"Web app root system property already set to different value: '" +
key + "' = [" + oldValue + "] instead of [" + root + "] - " +
"Choose unique values for the 'webAppRootKey' context-param in your web.xml files!");
}
System.setProperty(key, root);
servletContext.log("Set web app root system property: '" + key + "' = [" + root + "]");
}
对于 这个方法 ,如果使用过 org.springframework.web.util.WebAppRootListener 的同学,应该会熟悉
可以看到
org.springframework.web.util.WebAppRootListener
ch.qos.logback.ext.spring.web.WebLogbackConfigurer
org.springframework.web.util.Log4jWebConfigurer
会调用这个方法
那么这个方法到底是做什么的呢?
step1.从 servletContext init param中查找 webAppRootKey参数值
step2:如果没有配置 webAppRootKey 那么使用 "webapp.root",从 java.lang.System.getProperty(String) 查到值
step3:如果从 System Property 得到的值 不是null,并且 值不等于 servletContext.getRealPath("/")
那么就抛
throw new IllegalStateException(
"Web app root system property already set to different value: '" +
key + "' = [" + oldValue + "] instead of [" + root + "] - " +
"Choose unique values for the 'webAppRootKey' context-param in your web.xml files!")
step4:设置属性到JVM Property
System.setProperty(key, root);
好,分析完了 WebUtils.setWebAppRootSystemProperty(ServletContext)
继续看 ch.qos.logback.ext.spring.web.WebLogbackConfigurer.initLogging(ServletContext)
从 servletContext 获得 logbackConfigLocation参数
如果不是null, 那么 调用 org.springframework.util.SystemPropertyUtils.resolvePlaceholders(String)
来解析这个配置参数值
也就是说, logbackConfigLocation配置的路径支持 ${}这样的写法
注意 : org.springframework.util.SystemPropertyUtils.resolvePlaceholders(String) 调用的是 org.springframework.util.SystemPropertyUtils.SystemPropertyPlaceholderResolver
而这个 Resolver只会使用 JVM properties 以及操作系统的env 环境变量
我了个去咧, 要是使用的是 ServletContextPropertyUtils org.springframework.web.util.ServletContextPropertyUtils.ServletContextPlaceholderResolver就好了
大家来看看
org.springframework.web.util.Log4jWebConfigurer.initLogging(ServletContext) 就是使用的 ServletContextPropertyUtils
话又说回来了 ,org.springframework.web.util.ServletContextPropertyUtils @since 3.2.2
期待 LogbackConfigListener 升级吧
相关推荐
标题中的“【飞天奔月出品】windows版nginx 快速操控神器(启动start,关闭stop,重启restart) 批处理”指的是一个专为Windows操作系统设计的Nginx管理工具,它通过批处理脚本实现了Nginx服务的便捷启动、停止和重启...
4. **市场与竞争**:分析所在行业的市场环境,竞争对手的情况,以及公司市场份额的变化。 5. **产品与服务**:介绍主要产品和服务的研发进展,新产品的推出情况,以及现有产品的市场反馈。 6. **研发活动**:阐述...
奔月生物:2021年半年度报告.PDF
从文化视角分析,《奔月》揭示了中国传统文化中的某些消极因素。鲁迅将国民性概括为“愚弱”,表现为缺乏是非观念和不敢抗争的懦弱。嫦娥的冷漠、老太太的愚昧、逢蒙的狡诈,都在一定程度上映射了这种国民性。鲁迅借...
4. **报告结构**:报告包含了多个章节,如公司概况、会计数据和财务指标摘要、管理层讨论与分析、重要事项、股本变动及股东情况、董事、监事、高级管理人员及核心员工情况、财务报告和财务报表附注等。这些章节提供...
4. **Web Workers**:为了提升游戏性能,开发者可能会使用Web Workers创建后台线程,处理计算密集型任务,如游戏逻辑计算,从而避免阻塞主线程,保证游戏流畅运行。 5. **离线缓存**:HTML5的离线存储功能允许游戏...
4. **物理引擎**:为了模拟火箭兔的跳跃、飞行等动作,游戏可能内置了一个简单的物理引擎,处理碰撞检测、重力、速度等物理属性。 5. **音频控制**:游戏中的音效播放可能使用`Audio`对象,通过控制播放、暂停、...
《H5游戏源码解析:奔月游戏》 在当今数字化时代,HTML5(简称H5)技术以其跨平台、轻量级、易部署的特点,成为制作网页游戏的热门选择。"奔月游戏"作为一款H5游戏,其源码为我们提供了一窥H5游戏开发的窗口。本文...
在奔月游戏中,可能使用canvas来绘制角色、背景、轨迹等元素,并通过定时更新画面来实现动画效果。 2. **Web Audio API**:HTML5提供了Web Audio API,用于处理和播放音频。游戏往往需要背景音乐和音效,这个API...
手绘实例:奔月 Photoshop3 图片处理 高级手绘技术技巧
【长娥奔月模板下载TIF】是一个与网页设计相关的资源,主要提供了一种以"长娥奔月"为主题的网页模版。这个模版可能是为了庆祝中国传统节日,如中秋节,或者用于讲述中国古老的神话故事。"长娥奔月"是中国文化中的...
【标题】"小游戏源码-火贱兔奔月.rar" 提供的是一个小型游戏的源代码,名为"火贱兔奔月"。这类源码通常用于教学、学习或游戏开发者的参考,帮助开发者理解游戏的基本架构和编程逻辑。 【描述】"小游戏源码-火贱兔...
这篇文档介绍了如何使用Adobe Photoshop软件创作一张奔月女孩的梦幻艺术照片效果。以下是详细步骤: 1. **新建文件与导入素材**: - 首先创建一个新文件,大小与素材1相同,命名为"奔月女孩"。 - 然后打开素材1,...
游戏源码分享下载 --- hjby.zipHTML5小游戏【火贱兔奔月--425款经典优秀H5小游戏合集】游戏源码分享下载 --- hjby.zipHTML5小游戏【火贱兔奔月--425款经典优秀H5小游戏合集】游戏源码分享下载 --- hjby.zipHTML5小...
《鲁迅的《奔月》:颠覆传统,开创审美新向度》 鲁迅的短篇小说《奔月》是其《故事新编》中的一篇,它颠覆了我们对古代神话的传统认知,尤其对嫦娥这一角色的刻画,使得这篇作品在文学史上占据了独特的地位。鲁迅...
综上所述,鲁迅的《奔月》不仅是对传统神话的颠覆,更是对现实社会的深刻剖析。通过将传统神圣凡俗化,鲁迅开辟了新的审美向度,体现了他的先锋精神。他的作品不仅是文学艺术的创新,也是对时代问题的敏锐洞察和批判...
4. **CSS3**: 虽然主要的视觉效果可能在Canvas上完成,但CSS3也可能用于游戏界面的样式设置,如按钮、得分面板、游戏提示等非动画元素的布局和样式。 5. **事件监听与处理**: JavaScript中的事件监听器用于捕捉用户...
在这个兔子奔月吃月饼游戏中,Canvas可能被用来绘制游戏场景,如月亮、兔子、月饼等元素,以及处理游戏中的动态效果,如兔子跳跃、月饼移动等。 JavaScript是HTML5游戏的核心,它负责处理游戏逻辑、用户交互以及...
4. 图片和音频资源:游戏中的图像素材(如角色、背景、图标)和音效文件,通常为PNG或SVG格式的图片,以及MP3或WAV格式的音频。 5. JSON或其他配置文件:可能包含游戏设置、关卡信息、道具数据等,方便调整和扩展...
初中语文文摘生活且看嫦娥咋奔月