`

【飞天奔月出品】剖析logback4:spring LogbackConfigListener

    博客分类:
  • log
阅读更多

看过我前面几个帖子的伙伴也许知道, logback会自动加载配置文件

 

那为毛,官方还会提供spring

ch.qos.logback.ext.spring.web.LogbackConfigListener 呢?

参见 

https://github.com/qos-ch/logback-extensions/blob/master/spring/src/main/java/ch/qos/logback/ext/spring/web/LogbackConfigListener.java

 

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 升级吧

 

 

 

  • 大小: 26.2 KB
  • 大小: 27.7 KB
  • 大小: 19.7 KB
  • 大小: 19.4 KB
  • 大小: 25.9 KB
0
1
分享到:
评论
1 楼 飞天奔月 2016-04-07  
从0.1.4 version 开始,使用Using spring servlet context property utils insted.


https://github.com/qos-ch/logback-extensions/pull/34/commits/520ab5ae2fb4b4ac4081cb2b37d08d30cc1f3a47

相关推荐

    【飞天奔月出品】windows版nginx 快速操控神器(启动start,关闭stop,重启restart) 批处理

    标题中的“【飞天奔月出品】windows版nginx 快速操控神器(启动start,关闭stop,重启restart) 批处理”指的是一个专为Windows操作系统设计的Nginx管理工具,它通过批处理脚本实现了Nginx服务的便捷启动、停止和重启...

    奔月生物:2021年半年度报告.rar

    4. **市场与竞争**:分析所在行业的市场环境,竞争对手的情况,以及公司市场份额的变化。 5. **产品与服务**:介绍主要产品和服务的研发进展,新产品的推出情况,以及现有产品的市场反馈。 6. **研发活动**:阐述...

    奔月生物:2021年半年度报告.PDF

    奔月生物:2021年半年度报告.PDF

    鲁迅《奔月》作品分析.pdf

    从文化视角分析,《奔月》揭示了中国传统文化中的某些消极因素。鲁迅将国民性概括为“愚弱”,表现为缺乏是非观念和不敢抗争的懦弱。嫦娥的冷漠、老太太的愚昧、逢蒙的狡诈,都在一定程度上映射了这种国民性。鲁迅借...

    奔月生物:2019年半年度报告.PDF

    4. **报告结构**:报告包含了多个章节,如公司概况、会计数据和财务指标摘要、管理层讨论与分析、重要事项、股本变动及股东情况、董事、监事、高级管理人员及核心员工情况、财务报告和财务报表附注等。这些章节提供...

    HTML5奔月游戏

    4. **Web Workers**:为了提升游戏性能,开发者可能会使用Web Workers创建后台线程,处理计算密集型任务,如游戏逻辑计算,从而避免阻塞主线程,保证游戏流畅运行。 5. **离线缓存**:HTML5的离线存储功能允许游戏...

    火箭兔奔月HTML5游戏源码

    4. **物理引擎**:为了模拟火箭兔的跳跃、飞行等动作,游戏可能内置了一个简单的物理引擎,处理碰撞检测、重力、速度等物理属性。 5. **音频控制**:游戏中的音效播放可能使用`Audio`对象,通过控制播放、暂停、...

    H5游戏源码 奔月游戏.zip

    《H5游戏源码解析:奔月游戏》 在当今数字化时代,HTML5(简称H5)技术以其跨平台、轻量级、易部署的特点,成为制作网页游戏的热门选择。"奔月游戏"作为一款H5游戏,其源码为我们提供了一窥H5游戏开发的窗口。本文...

    HTML5奔月游戏 源码.zip

    在奔月游戏中,可能使用canvas来绘制角色、背景、轨迹等元素,并通过定时更新画面来实现动画效果。 2. **Web Audio API**:HTML5提供了Web Audio API,用于处理和播放音频。游戏往往需要背景音乐和音效,这个API...

    手绘实例:奔月 Photoshop3 图片处理 高级手绘技术技巧.doc

    手绘实例:奔月 Photoshop3 图片处理 高级手绘技术技巧

    长娥奔月模板下载TIF

    【长娥奔月模板下载TIF】是一个与网页设计相关的资源,主要提供了一种以"长娥奔月"为主题的网页模版。这个模版可能是为了庆祝中国传统节日,如中秋节,或者用于讲述中国古老的神话故事。"长娥奔月"是中国文化中的...

    小游戏源码-火贱兔奔月.rar

    【标题】"小游戏源码-火贱兔奔月.rar" 提供的是一个小型游戏的源代码,名为"火贱兔奔月"。这类源码通常用于教学、学习或游戏开发者的参考,帮助开发者理解游戏的基本架构和编程逻辑。 【描述】"小游戏源码-火贱兔...

    Photoshop合成奔月女孩梦幻艺术照片效果.doc

    这篇文档介绍了如何使用Adobe Photoshop软件创作一张奔月女孩的梦幻艺术照片效果。以下是详细步骤: 1. **新建文件与导入素材**: - 首先创建一个新文件,大小与素材1相同,命名为"奔月女孩"。 - 然后打开素材1,...

    HTML5小游戏【火贱兔奔月-425款经典优秀H5小游戏合集】游戏源码分享下载 - hjby.zip

    游戏源码分享下载 --- hjby.zipHTML5小游戏【火贱兔奔月--425款经典优秀H5小游戏合集】游戏源码分享下载 --- hjby.zipHTML5小游戏【火贱兔奔月--425款经典优秀H5小游戏合集】游戏源码分享下载 --- hjby.zipHTML5小...

    析鲁迅《奔月》.docx

    《鲁迅的《奔月》:颠覆传统,开创审美新向度》 鲁迅的短篇小说《奔月》是其《故事新编》中的一篇,它颠覆了我们对古代神话的传统认知,尤其对嫦娥这一角色的刻画,使得这篇作品在文学史上占据了独特的地位。鲁迅...

    [鲁迅]析鲁迅《奔月》.docx

    综上所述,鲁迅的《奔月》不仅是对传统神话的颠覆,更是对现实社会的深刻剖析。通过将传统神圣凡俗化,鲁迅开辟了新的审美向度,体现了他的先锋精神。他的作品不仅是文学艺术的创新,也是对时代问题的敏锐洞察和批判...

    HTML5兔子奔月吃月饼游戏源码

    4. **CSS3**: 虽然主要的视觉效果可能在Canvas上完成,但CSS3也可能用于游戏界面的样式设置,如按钮、得分面板、游戏提示等非动画元素的布局和样式。 5. **事件监听与处理**: JavaScript中的事件监听器用于捕捉用户...

    HTML5兔子奔月吃月饼游戏源码.zip

    在这个兔子奔月吃月饼游戏中,Canvas可能被用来绘制游戏场景,如月亮、兔子、月饼等元素,以及处理游戏中的动态效果,如兔子跳跃、月饼移动等。 JavaScript是HTML5游戏的核心,它负责处理游戏逻辑、用户交互以及...

    H5小游戏源码 火贱兔奔月.zip

    4. 图片和音频资源:游戏中的图像素材(如角色、背景、图标)和音效文件,通常为PNG或SVG格式的图片,以及MP3或WAV格式的音频。 5. JSON或其他配置文件:可能包含游戏设置、关卡信息、道具数据等,方便调整和扩展...

    初中语文文摘生活且看嫦娥咋奔月

    初中语文文摘生活且看嫦娥咋奔月

Global site tag (gtag.js) - Google Analytics