Java 停止引用的服务后终止OSGI蓝图捆绑包

Java 停止引用的服务后终止OSGI蓝图捆绑包,java,osgi,osgi-bundle,blueprint-osgi,Java,Osgi,Osgi Bundle,Blueprint Osgi,我有这样的问题。我有两个OSGI蓝图包。其中一个类似于服务,另一个正在使用它。我在卡拉夫上运行它们。所以,我想实现功能,这样当我停止服务时,我的另一个包也应该停止。 我的xml com.myslyv4uk.weather.api.WeatherService 跳过Java代码。我只想说ShowWeatherService使用WeatherService打印随机数。它们都有启动/停止方法。我需要以这种方式实现配置或功能,以便在从karaf卸载WeatherService捆绑包后,也停止Show

我有这样的问题。我有两个OSGI蓝图包。其中一个类似于服务,另一个正在使用它。我在卡拉夫上运行它们。所以,我想实现功能,这样当我停止服务时,我的另一个包也应该停止。 我的xml


com.myslyv4uk.weather.api.WeatherService

跳过Java代码。我只想说ShowWeatherService使用WeatherService打印随机数。它们都有启动/停止方法。我需要以这种方式实现配置或功能,以便在从karaf卸载WeatherService捆绑包后,也停止ShowWeatherService。问题是,我无法从WeatherService引用到ShowWeatherService,因为它将是循环引用,因为此捆绑包无法启动。我该怎么办?如何从其他捆绑包终止捆绑包?

当此服务停止时,我不会停止需要服务的捆绑包。这不是OSGi中应该处理的方式

相反,您的showWeatherImpl捆绑包可以使用http白板模式作为servlet提供自己。这意味着它提供了一个实现servlet的服务。如果强制服务引用失败,Blueprint将自动注销捆绑包中的所有服务

当然,如果您使用showWeatherImpl中bean中的java代码将自己注册为一个servlet,那么这并没有帮助。在这种情况下,您可以使用服务引用回调,它将在服务出现和消失时通知您

当然,正如Grzegorz所提到的,声明性服务在默认情况下比blueprint更具动态性,并且处理此类情况的能力也更好。

WARNING 在这个回答中,我解释了当所需服务消失时如何停止Blueprint捆绑包。此代码按预期工作,但由于各种原因,它是一个坏主意


您可以在绑定/取消绑定服务时注册侦听器,并在删除服务时执行操作。这是一个如何做到这一点的例子

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"
    xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd ">

    <bean id="referenceListener" class="your.ReferenceListener">
        <property name="bundleContext" ref="blueprintBundleContext"/>
    </bean>

    <reference id="weatherService"
               availability="mandatory"
               interface="com.myslyv4uk.weather.api.WeatherService">
        <reference-listener ref="referenceListener"
                            unbind-method="unbind" />
    </reference>

    <bean id="showWeatherImpl" class="com.myslyv4uk.client.impl.ShowWeatherServiceImpl"
        init-method="start" destroy-method="stop" >
        <argument ref="weatherService" />
    </bean>

</blueprint>

移除服务时调用ReferenceListenerbean。通过注入bundle上下文,您可以停止bundle本身:

public class ReferenceListener {

private Logger log; // set this up
private BundleContext bundleContext;

public void setBundleContext(BundleContext bundleContext) {
    this.bundleContext = bundleContext;
}

// Called when the service is injected
public void bind(ServiceReference<?> sr) {
    log.info("Bind of ServiceReference {} to bundle {}",
            sr, bundleContext.getBundle());
}

// Called when the service is removed
public void unbind(ServiceReference<?> sr) {
    log.info("Unbind of ServiceReference {} from bundle {}",
            sr, bundleContext.getBundle());
    try {
        if (bundleContext.getBundle().getState() == Bundle.ACTIVE) {
            log.warn("Bundle {} will be stopped after unbind of mandatory ServiceReference {}",
                    bundleContext.getBundle(), sr);
            bundleContext.getBundle().stop();
        }

    } catch (BundleException e) {
        log.error("Cannot stop bundle {} after unbind of ServiceReference {}",
                bundleContext.getBundle().getBundleId(),
                sr,
                e);
    }
}
}
公共类引用列表器{
专用记录器日志;//设置此日志
私有BundleContext BundleContext;
public void setBundleContext(BundleContext BundleContext){
this.bundleContext=bundleContext;
}
//注入服务时调用
公共无效绑定(ServiceReference sr){
info(“将ServiceReference{}绑定到bundle{}”,
sr,bundleContext.getBundle());
}
//删除服务时调用
公共无效解除绑定(服务参考sr){
info(“将ServiceReference{}从绑定{}中解除绑定”,
sr,bundleContext.getBundle());
试一试{
if(bundleContext.getBundle().getState()==Bundle.ACTIVE){
log.warn(“强制ServiceReference{}解除绑定后,捆绑{}将停止”,
bundleContext.getBundle(),sr);
bundleContext.getBundle().stop();
}
}捕获(捆绑例外e){
log.error(“解除ServiceReference{}绑定后无法停止绑定{}”,
bundleContext.getBundle().getBundleId(),
高级,
e) );
}
}
}

此解决方案可行,但也有一些缺点,例如,如果重新启动容器,服务将被删除,从而将捆绑包设置为停止状态。

检查。您可以根据OSGi服务(以及其他服务)的存在/不存在来激活/停用“组件”@GrzegorzGrzybek谢谢您的评论,但据我所知,这是声明性服务。我用的是蓝图。重写到声明性服务是我想避免的最后一种手段,如果强制服务引用失败,那么对该实例的任何后续调用都将被阻止(因为您从未获得服务,而是服务的blueprint代理),并最终引发
ServiceUnavailableException
。是的。这是真的。因此,只有当你有一个完整的服务链时,这才有效。OSGiHTTP白板就是这样一个例子。在其他情况下,当bean的依赖项不可用时,一旦从外部接到对bean的调用,它就会阻塞。对我来说,这就是为什么我尝试只在可能的情况下使用DS的原因之一。以编程方式停止您自己的捆绑包是一件可怕的事情。在StackOverflow上,你不应该总是给提问者他们想要的东西,特别是如果他们要求的东西会伤害他们的话。@NeilBartlett谢谢你的评论,我同意你的观点,并在帖子顶部加上警告。由于这是OP所要求的,我将把它留在这里作为参考,欢迎使用任何其他与Blueprint兼容的解决方案:-)谢谢,@AlessandroDaRugna您的回答给了我一个如何解决生产中问题的提示。实际上,在停止服务时,我需要终止一些逻辑,在这种情况下,解除绑定的方法帮助了我。谢谢
public class ReferenceListener {

private Logger log; // set this up
private BundleContext bundleContext;

public void setBundleContext(BundleContext bundleContext) {
    this.bundleContext = bundleContext;
}

// Called when the service is injected
public void bind(ServiceReference<?> sr) {
    log.info("Bind of ServiceReference {} to bundle {}",
            sr, bundleContext.getBundle());
}

// Called when the service is removed
public void unbind(ServiceReference<?> sr) {
    log.info("Unbind of ServiceReference {} from bundle {}",
            sr, bundleContext.getBundle());
    try {
        if (bundleContext.getBundle().getState() == Bundle.ACTIVE) {
            log.warn("Bundle {} will be stopped after unbind of mandatory ServiceReference {}",
                    bundleContext.getBundle(), sr);
            bundleContext.getBundle().stop();
        }

    } catch (BundleException e) {
        log.error("Cannot stop bundle {} after unbind of ServiceReference {}",
                bundleContext.getBundle().getBundleId(),
                sr,
                e);
    }
}
}