码迷,mamicode.com
首页 > 其他好文 > 详细

OSGi实战总结

时间:2015-02-10 22:55:14      阅读:373      评论:0      收藏:0      [点我收藏+]

标签:

  1、类加载问题ClassNotFoundException

  在OSGi环境中,ClassNotFoundException是最常见的,主要是因为在OSGi环境,每一个Bundle都有自己独立的ClassLoader,而Bundle之间的通信交互是通过依赖关系(import/export)来控制,随着系统越来越复杂,依赖关系也就越来越复杂(尤其是在一些没有严格控制依赖的系统中),因此,出现这种异常的频率非常高。类似的,也经常会出现NoClassDefDoundErr、ClassCastException异常。

  遇到这类问题,直接从异常日志是很难精确定位根源的,必须打开OSGi提供的调试日志(详细调试选项可以参考OSGi项目的Debug.java类),这样从日志就可以看出是哪个Bundle加载哪个类遇到什么问题。

  但是,如果我们在启动服务的时候就打开这些调试日志,系统启动会非常慢,因为输出了很多的日志,运行期也同样非常慢。那么,就需要一个可以动态开关调试日志的功能。我们可以通过扩展OSGi的CommandProvider,实现一个自己的命令,然后可以动态的修改Debug.java属性值来达到目的。

例如修改调试参数的命令:

public class DebugCommandProvider implements CommandProvider {
    public void _debug(CommandInterpreter ci) {
        String debug_field = ci.nextArgument();
        String tip = ci.nextArgument();
        if (null != debug_field && debug_field.trim().length() > 0) {
            if (null != tip && tip.trim().length() > 0) {
                try {
                    debug_field = debug_field.trim().toUpperCase();
                    Field field = Debug.class.getDeclaredField(debug_field);
                    boolean flag = tip.trim().toUpperCase().equals("ON");
                    field.set(null, flag);
                    ci.print("设置Debug参数:[" + debug_field + "=" + flag + "]\r\n");
                } catch (Exception e) {
                    ci.print("设置Debug参数时出现异常:" + e.getMessage() + "\r\n");
                }
            } else {
                ci.println("未指定参数,例如: debug debug_loader <on|off>");
            }
        } else {
            ci.println("未指定参数,例如: debug debug_loader <on|off>");
        }
    }
    ...
}    

 

  2、OSGi调试环境扩展

  为了让开发人员能知道OSGi容器里面的方方面面,框架本身提供了一个调试控制台,通过命令可以查看容器装载的Bundle、服务、依赖等所有需要知道的系统服务信息。

  在开发环境下,通过JVM参数-console开启,直接在Eclipse控制台就可以输入命令;如果不希望命令输出和控制台日志混合的话,可以单独指定一个端口。

  通常,生产环境就会指定一个端口来隔离应用日志,然后telnet进去操作命令。

  例如生产环境开启控制台的配置:

<servlet-class>org.eclipse.equinox.servletbridge.BridgeServlet</servlet-class>    
  <init-param>
    <param-name>enableFrameworkControls</param-name>
    <param-value>true</param-value>    
  </init-param>
  <init-param>
    <param-name>commandline</param-name>
    <param-value>-console 9999</param-value>    
  </init-param>
</servlet>

  但是,这个配置不能用在集群下,会端口冲突,动态web配置显得麻烦。

  然后,一个Web形式的OSGi控制台就应该出来了,主要实现就是提供一个命令的重定向,将输入的命令重定向到OSGi控制台,然后将命令结果输出到web页面。核心就是围绕org.eclipse.osgi.framework.internal.core.FrameworkConsole类传参,并指定好PrintWriter。

  3、服务异常自动分析报告

  无论什么好东西,如果不好好的使用的话,时间久了都会把它玩烂。OSGi就是如此,如果模块、依赖起初没有严格规划好,越到后面,遇到的问题就越多,也越复杂,维护成本非常高。

  但是,有些问题可以根据经验和具体实现来自动分析,然后得出一份异常分析报告并给出相应的解决方案,好处就是根据分析报告可以快速定位解决问题。

  报告可以包括参数配置信息、Bundle依赖校验结果、Bundle启动异常、bean异常、上下文发布异常、资源注册信息等

  值得一提的是Bundle依赖校验,通常都是采用eclipse自带的依赖校验功能,可以直接看出不满足的依赖信息。但是,生成环境在没有eclipse的情况就没那么简单了。虽然OSGi会将依赖校验不满足的信息写到一个日志文件里面,但是太冗余,对于问题定位很多时候都没什么帮助。

  举个例子,如果有一个依赖链涉及很多的Bundle,而处于这个链中间的某个Bundle依赖有问题导致不能正常解析,结果就导致依赖它的Bundle(包括间接的)都不能解析。笨办法就是操作控制台,一个一个排查(通过diag命令可以看未满足约束信息),简单的情况可以整出结果来,稍微复杂的情况就绕不出来了。最后实在不行就只有将项目拷贝到eclipse中看校验结果。

  该问题的终极解决办法就是在框架装载完Bundle后自动输出校验结果,而且只输出依赖链的叶子节点信息,这样就可以一目了然的发现是哪个Bundle导致的依赖问题。核心就是围绕org.eclipse.osgi.service.resolver.State类,它有一个方法getResolverErrors()可以根据BundleDescription来获取解析错误信息,然后对这些信息进行分析得出结果。

  4、分层启动

  如果一个系统比较庞大,并且模块依赖比较规范,比如系统分了平台层、业务层,只有业务层能依赖平台层,这样就可以优先启动平台层,然后再启动业务层。通过这样的启动可以减少服务依赖的等待时间,并且如果平台层启动发现问题时,可以停止后续的启动过程,对于问题的定位效率也是非常大的提升。

  OSGi有一个StartLevel的服务,首先约定Bundle的启动级别,然后通过调整框架级别就可以实现分层启动了。

  5、OSGi与Spring的整合问题

  可以通过SpringDM进行整合。

  但是也有一些优化,比如在对Bundle的Class进行扫描的时候,同时会对它依赖的Bundle进行扫描,其实这是多余的,只关心当前Bundle的类,其他的即使扫描出来也没有任何用处,但是该操作又比较耗时。

  6、OSGi部署优化

  在集群环境下,部署的web应用都会同步到各个节点,如果应用较大的话,同步操作也比较耗时。

  如果节点都在同一个机器上的话,可以让所有节点都从同一个Bundle插件目录读取,然后将里面的Bundle安装到OSGi框架。

OSGi实战总结

标签:

原文地址:http://www.cnblogs.com/forrestajun/p/osgiexperience.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!