ClassCastException On JBOSS OSGI 7.1



我的项目使用JBOSS OSGI 7.1。我有两个捆绑包:

usermanagement (service provider)
jerseyBundle (service consumer)

当我部署并启动CCD_ 2捆绑包时,然后部署并启动球衣捆绑包。

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;
}
}

我使用蓝图注册服务。

我试着取消服务,但没有解决这个问题。

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();
}
}

有没有任何方法可以重新部署服务提供商捆绑包,而不需要重新部署服务消费者捆绑包?

观察到的行为的原因可能是OSGi按捆绑包缓存服务对象。因此,如果您执行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)或蓝图这样的框架的原因。这样可以确保在服务来来去去时重新注入服务并重新启动组件。由于您已经在提供者端使用蓝图,您可能也会尝试在客户端使用它。蓝图客户不应该出现您所观察到的问题。

Btw。blueprint和DS处理服务动态的方式非常不同。Blueprint注入一次代理,然后只替换代理中的服务对象,而DS将真正重新启动您的用户组件。

最新更新