OSGi实战总结

  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框架。

时间: 2024-08-04 03:44:22

OSGi实战总结的相关文章

osgi实战学习之路:8. Service-3之ServiceTracker

通过ServiceTracker可以对查找的Service进行扩展 下面的demo引入装饰器模式对Service进行日志的扩展 demo: Provider student-manage/Activator.java package com.demo.service; import java.util.Dictionary; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; import org

osgi实战学习之路:5.生命周期及利用命令、装饰者模式实现基于socket交互Bundle命令demo

生命周期中关键3个类: BundleActivator 入口点,类似main方法 BundleContext Bundle上下文对象,在运行期间,为应用程序提供操作osgi框架的方法 Bundle 代表一个已安装的Bundle 接口说明: BundleActivator: public interface BundleActivator { public void start(BundleContext context) throws Exception; public void stop(Bu

osgi实战学习之路:6. Service-1

什么是Service? 它是注册到osgi的一个java对象 Service注册: 通过BundleContext::registerService(java.lang.String[] clazzes, java.lang.Object service, java.util.Dictionary properties)  Service查找及使用: 通过BundleContext::getServiceReference(java.lang.String clazz),返回ServiceRef

osgi实战学习之路:7. Service-2之ServiceListener

ServiceListener三种状态: ServiceEvent.REGISTERED ServiceEvent.MODIFIED ServiceEvent.UNREGISTERING 基于ServiceListener实现服务查找的demo Provider student-manage/Activator.java package com.demo.service; import java.util.Dictionary; import java.util.HashMap; import

osgi实战学习之路:2. maven+maven-bundle-plugin+karaf搭建osgi之HelloWorld

环境准备: jdk版本 jdk:1.7 karaf: 版本:apache-karaf-3.0.1 下载地址: http://pan.baidu.com/s/1qWM4Y1u http://karaf.apache.org/ 配置本地仓库: 参考:http://blog.csdn.net/wobendiankun/article/details/25333113 启动karaf: karaf_home/bin/karaf.bat 启动成功如下: 安装 mvn-hello-provider 到本地仓

osgi实战学习之路:4.Bundle

源代码下载 Bundle是什么? Bundle是一个标准的jar,只是在META-INF/MANIFEST.MF中加入Bundle元数据的描述 Bundle元数据 标识 Bundle-ManifestVersion: 2 Bundle-Name: student-model Bundle-SymbolicName: com.demo.student-model Bundle-Version: 0.0.1.SNAPSHOT Export-Package 导出Bundle的某些包中的代码让其它Bun

osgi实战学习之路:3. osgi分层概念及相互合作demo

源代码下载 分层: modual: 主要作用于包级管理与共享代码 lifecycle: 主要作用于运行期间的模块管理与访问osgi底层框架 service: 主要作用于多模块之间的相互通信 demo: hello-provider/pom.xml <?xml version="1.0"?> <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.or

OSGI实战第一章

第一章         解开OSGI的面纱 OSGI是什么?是Java平台的一个模块化层. 模块化:软件应用程序的代码被分割为表示独立内容的逻辑单元,可简化开发,可通过强化逻辑模块的界限来提高可维护性. Java模块化的不足 a)         Java使用访问修饰符(如public.protected.private和包级私有),解决底层面向对象封装,而不是逻辑系统划分. 比如,如果需要代码在多个包之间课件,那么包内的代码必须声明为public,那么所有的模块都可以使用这个public类.这

Java动态模型系统OSGi实战讲解

课程大纲 1:OSGi概要介绍及课程计划 2:Apache Felix介绍 3:OSGi helloword 4:OSGi Bundle 5:Bundle的事件监听 6:OSGi的类加载机制 7:OSGi服务的介绍 8:OSGi服务跟踪器 9:OSGi服务的事件监听 10:OSGi服务钩子 11:OSGi声明式服务 12:Apache Aries 13:Apache Karaf 14:Maven Bundle Plugin 插件 15:OSGi Blueprint(一) 16:OSGi Blue