我将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();
}
}
有没有办法重新部署服务提供商捆绑包,不需要重新部署服务消费者捆绑包吗?
答案 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将真正重新启动用户组件。