JBOSS OSGI 7.1上的ClassCastException

时间:2014-02-22 09:59:50

标签: jboss osgi

我将JBOSS OSGI 7.1用于我的项目。 我有2个包:

usermanagement (service provider)
jerseyBundle (service consumer)

当我部署并启动usermanagement捆绑时, 然后部署并启动jersey bundle。

jerseyBundle getServiceReference() successful. 

然后。 我尝试重新部署并重新启动usermanagement。然后刷新所有包。

JerseyBundle getServiceReference() with Exception: "ClassCastException"

这是我用来获取服务的代码:

public <T> T getService(Class<T> type,List<ServiceReference> _sref) {
try {
    ServiceReference sref = bundleContext.getServiceReference(type.getName());
    if(sref != null)
    {
        _sref.add(sref);
    }

    return type.cast(bundleContext.getService(sref));
} catch (Exception ex) {
    ex.printStackTrace();
    return null;
}

}

我使用蓝图来注册服务。

我试图ungetservice但它没有解决这个问题。

public void  unGetService(List<ServiceReference> _sref) {
try{    
 while(_sref != null && _sref.size() >0 )
 {
     System.err.println("==============" + bundleContext.ungetService(_sref.remove(0)));

 }
}catch(Exception ex){
    ex.printStackTrace();
}
}

有没有办法重新部署服务提供商捆绑包,不需要重新部署服务消费者捆绑包吗?

1 个答案:

答案 0 :(得分:1)

观察到的行为的原因可能是OSGi通过bundle缓存服务对象。因此,如果您执行bundleContext.getService(sref),那么OSGI将在内部存储此对象,并始终返回相同的内容,直到您执行ungetService。

因此,当您更新包含接口并刷新客户端的服务包时,您将拥有该接口的新类。如果现在对新接口执行旧服务对象的转换,则会发生ClassCastException。

解决此问题的一种方法是仅在短时间内使用服务对象,然后取消设置。像这样:

ServiceReference sref = bundleContext.getServiceReference(type.getName());
myO = type.cast(bundleContext.getService(sref));
doStuff(myO);
bundleContext.ungetService(sref)

当然,这对于不频繁的通话来说是切实可行的,因为你有一些开销。

另一种方法是使用ServiceTracker并对服务添加和删除做出反应。因此,例如,您可以将一个服务注入到您的类中,该服务执行“doStuff”并在有更改时删除/替换服务。尽管如此,这很难做到。

实际上,这就是为什么存在声明性服务(DS)或蓝图等框架的原因。这些确保在服务来来往往时重新注入服务并重新启动组件。 由于您已经在提供者端使用蓝图,因此您也可以尝试在客户端使用它。蓝图客户端不应该遇到您遇到的问题。

顺便说一下。蓝图和DS处理服务动态的方式截然不同。 Blueprint注入一次代理,然后只替换代理中的服务对象,而DS将真正重新启动用户组件。