`
pzx888
  • 浏览: 13888 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Logback+Osgi配置自动更新问题

    博客分类:
  • OSGI
阅读更多
软件版本
Logback-core-0.9.30
Logback-classic-0.9.30
Osgi equinox
Eclipse 3.7.2
存在问题
logback.xml配置文件,设置自动检测配置更新,<configuration scan="true"  debug="true">,但是启动后,修改配置文件没有自动更新。比如:
<logger name="com.company.server.main" >
		<level value="DEBUG" />
</logger>

level修改为INFO,debug级别日志继续输出
问题分析
经阅读源码,跟踪调试,反复验证,确认是logback与osgi配合使用时,存在的缺陷,将配置文件放在类路径下,比如放在src下,logback会自动在classpath中找到该文件,但是自动检测更新不起作用。(当然是有解决办法的,请看下文)
当把<configuration scan="true"  debug="true">,debug设置为true时,会输出logback内部的一些调试信息。项目启动时会输出:
14:06:35,846 |-INFO in ReconfigureOnChangeFilter{invocationCounter=0} - Will scan for changes in [[D:\workspace\fileaccess\src\test\resources\logback.xml]] every 60 seconds. 
14:06:35,846 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - Adding ReconfigureOnChangeFilter as a turbo filter

很明显,这段日志指的是,每60s会检测指定路径下的配置文件是否有变化,该路径就是你配置文件的绝对路径。
而osgi启动时,会怎么样呢?
14:32:58,509 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [logback.xml] at [bundleresource://62.fwk918077175/logback.xml]
14:32:58,510 |-WARN in ch.qos.logback.classic.LoggerContext[default] - Resource [logback.xml] occurs multiple times on the classpath.
14:32:58,510 |-WARN in ch.qos.logback.classic.LoggerContext[default] - Resource [logback.xml] occurs at [bundleresource://62.fwk918077175/logback.xml]
14:32:58,510 |-WARN in ch.qos.logback.classic.LoggerContext[default] - Resource [logback.xml] occurs at [bundleresource://62.fwk918077175:38/logback.xml]
14:32:58,530 |-INFO in ch.qos.logback.core.joran.spi.ConfigurationWatchList@239a029e - URL [bundleresource://62.fwk918077175/logback.xml] is not of type file
14:32:58,579 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - debug attribute not set
14:32:58,579 |-INFO in ReconfigureOnChangeFilter{invocationCounter=0} - Will scan for changes in [[]] every 60 seconds. 

请注意以上日志,自动检测的目标是空的,先说结果,就是不能再侦测到任何更新了。原因是osgi自动给配置文件一个URL[bundleresource://62.fwk918077175:38/logback.xml],这导致logback在将该URL放入WatchList时,解析为NULL。而正常的URL应该是这种格式:file://D:\workspace\fileaccess\src\test\resources\logback.xml。 更具体的分析,在本文最后,有兴趣的同学可以继续看看。
先来说说解决办法
问题的原因,是解析文件URL出错,那么如何避免这个问题,办法就是logback的显式指定配置文件路径的办法。
在java启动参数中,加上-Dlogback.configurationFile=D:\eclipse-64bit\*\logback.xml(你自己的配置文件路径),这样配置文件就能被logback成功的加到watchlist中去了。就可以自动检测配置更新了。

详细分析
分析涉及logback源码,可以去官网http://logback.qos.ch/下载。
只提几个启动过程中,配置初始化的关键类,按调用先后顺序。
classic包ContextInitializer类
public void autoConfig() throws JoranException {
    StatusListenerConfigHelper.installIfAsked(loggerContext);
    URL url = findURLOfDefaultConfigurationFile(true);
    if (url != null) {
      configureByResource(url);
    } else {
      BasicConfigurator.configure(loggerContext);
    }
  }
public void configureByResource(URL url) throws JoranException {
    if (url == null) {
      throw new IllegalArgumentException("URL argument cannot be null");
    }
    if (url.toString().endsWith("groovy")) {
      if (EnvUtil.isGroovyAvailable()) {
        // avoid directly referring to GafferConfigurator so as to avoid
        // loading  groovy.lang.GroovyObject . See also http://jira.qos.ch/browse/LBCLASSIC-214
        GafferUtil.runGafferConfiguratorOn(loggerContext, this, url);
      } else {
        StatusManager sm = loggerContext.getStatusManager();
        sm.add(new ErrorStatus("Groovy classes are not available on the class path. ABORTING INITIALIZATION.",
                loggerContext));
      }
    }
    if (url.toString().endsWith("xml")) {
      JoranConfigurator configurator = new JoranConfigurator();
      configurator.setContext(loggerContext);
      configurator.doConfigure(url);
    }
  }

Core包GenericConfigurator类
f
inal public void doConfigure(URL url) throws JoranException {
    try {
      informContextOfURLUsedForConfiguration(getContext(), url);
      URLConnection urlConnection = url.openConnection();
      // per http://jira.qos.ch/browse/LBCORE-105
      // per http://jira.qos.ch/browse/LBCORE-127
      urlConnection.setUseCaches(false);

      InputStream in = urlConnection.getInputStream();
      doConfigure(in);
      in.close();
    } catch (IOException ioe) {
      String errMsg = "Could not open URL [" + url + "].";
      addError(errMsg, ioe);
      throw new JoranException(errMsg, ioe);
    }
  }
static public void informContextOfURLUsedForConfiguration(Context context, URL url) {
    ConfigurationWatchListUtil.setMainWatchURL(context, url);
  }

Core包ConfigurationWatchListUtil类
public static void setMainWatchURL(Context context, URL url) {
    ConfigurationWatchList cwl = getConfigurationWatchList(context);
    if (cwl == null) {
      cwl = new ConfigurationWatchList();
      cwl.setContext(context);
      context.putObject(CoreConstants.CONFIGURATION_WATCH_LIST, cwl);
    } else {
      cwl.clear();
    }
    setConfigurationWatchListResetFlag(context, true);
    cwl.setMainURL(url);
  }

Core包ConfigurationWatchList类
public void setMainURL(URL mainURL) {
    // main url can be null
    this.mainURL = mainURL;
    if (mainURL != null)
      addAsFileToWatch(mainURL);
  }
private void addAsFileToWatch(URL url) {
    File file = convertToFile(url);
    if (file != null) {
      fileWatchList.add(file);
      lastModifiedList.add(file.lastModified());
    }
  }
@SuppressWarnings("deprecation")
  File convertToFile(URL url) {
    String protocol = url.getProtocol();
    if ("file".equals(protocol)) {
      File file = new File(URLDecoder.decode(url.getFile()));
      return file;
    } else {
      addInfo("URL [" + url + "] is not of type file");
      return null;
    }
  }

解析就是convertToFile这里出的问题,URL[bundleresource://62.fwk918077175:38/logback.xml],会返回NULL。所以就没有加入到fileWatchList里面。

ReconfigureOnChangeFilter是检测配置更新的关键类,文章最初提到的日志里,输出每60s检测一次,就是它输出的,它取的watchList就是fileWatchList。
所以,问题已经很明显了。
更多的,请阅读源码。
分享到:
评论

相关推荐

    osgi数据库连接demo

    最后,`logback-core-1.0.0.jar`是日志记录库,用于记录应用程序的运行日志,这对于调试和监控OSGi环境中的应用程序非常重要。 总结来说,这个“osgi数据库连接demo”展示了如何在OSGi环境中配置C3P0连接池,使用...

    killbill-osgi-bundles-lib-slf4j-osgi-0.8.4.zip

    SLF4J 的 OSGi 版本允许 KillBill 的不同组件根据需要加载各自的日志实现,如 Logback 或者 Log4j,以实现模块化和可配置的日志策略。 【描述】"qunit-mojo.zip, Qunit Mojo 是一个 Maven 插件,用于快速轻松地创建...

    读properties和事务demo

    总的来说,这个“读properties和事务demo”是一个结合了OSGi服务管理、Spring框架的事务处理以及properties配置管理的实例,旨在帮助开发者理解如何在复杂环境中处理配置文件和确保数据一致性。通过分析和实践这个...

    Java_一款面向泛前端产品研发全生命周期的效率平台.zip

    而"说明.txt"文件则可能详细介绍了如何使用这个工具或平台,包括安装步骤、配置方法以及常见问题解答。 通过充分利用Java平台及其生态系统,前端研发团队可以构建高效、稳定且易于维护的产品,降低开发成本,提升...

    Java常用的插件API整理以及基于JDK的一些方法封装库.zip

    8. Logback与SLF4J:日志记录框架,提供了高效的日志处理和灵活的日志配置,优于JDK的java.util.logging。 这些库通过封装和优化JDK的API,提高了开发者的生产力,同时也降低了代码的复杂度。在日常开发中,理解并...

    开发常用jar4

    它提供了一种动态的类加载机制,使得不同的组件可以独立升级和更新,而不影响整个应用程序。OSGi容器如Apache Felix和Equinox,帮助开发者实现模块化架构,提高软件的可维护性和可扩展性。 2. **Project Lombok**:...

    Java与springboot实现金融风控系统

    SpringBoot是基于Spring框架的一个轻量级开发工具,它简化了配置,提供了自动配置功能,使得开发者可以快速构建微服务应用。在风控系统中,SpringBoot可以帮助我们构建RESTful API,实现服务的解耦和模块化,同时,...

    【白雪红叶】JAVA学习技术栈梳理思维导图.xmind

    自动化代码检查 sonar 代码规范 阿里巴巴Java开发规范手册 UMPAY——编码规范 日志规范 异常规范 网络 协议 TCP/IP HTTP hession file HTTPS 负载均衡 容器 JBOSS tomcat resin jetty 容灾 ...

Global site tag (gtag.js) - Google Analytics