【问题标题】:Terminating OSGI blueprint bundle after stop of referenced service停止引用服务后终止 OSGI 蓝图包
【发布时间】:2018-03-25 10:11:09
【问题描述】:

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

    <?xml version="1.0" encoding="UTF-8"?>
<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 ">

    <reference id="weatherService" availability="mandatory" interface="com.myslyv4uk.weather.api.WeatherService" />  

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

</blueprint>

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd ">

    <bean id="weatherServiceImpl" class="com.myslyv4uk.weather.impl.WeatherServiceImpl"
        init-method="start" destroy-method="stop" />

    <service ref="weatherServiceImpl">
        <interfaces>
            <value>com.myslyv4uk.weather.api.WeatherService</value>
        </interfaces>
    </service>  
</blueprint>

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

【问题讨论】:

  • 检查OSGi SCR。您可以根据是否存在 OSGi 服务(以及其他)来激活/停用“组件”
  • @GrzegorzGrzybek 感谢您的评论,但据我了解,这是声明性服务。我正在使用蓝图。重写为声明式服务是我想避免的最后手段

标签: java osgi osgi-bundle blueprint-osgi


【解决方案1】:

警告

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


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

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

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

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

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

【讨论】:

  • 以编程方式停止你自己的包是一件可怕的事情。在 StackOverflow 上,你不应该总是给提问者他们想要的东西,尤其是当他们要求的东西会伤害他们时。
  • @NeilBartlett 感谢您的评论,我同意您的意见,并在帖子顶部发出警告。由于这是 OP 所要求的,因此我将其留在这里以供参考,欢迎任何其他与蓝图兼容的解决方案 :-)
  • 谢谢,@AlessandroDaRugna 你的回答给了我一个提示如何解决我在生产中的问题。实际上,在停止服务时,我需要终止一些逻辑,而 unbind0method 在这种情况下帮助了我。非常感谢
【解决方案2】:

当该服务出现故障时,我不会停止需要该服务的捆绑包。这不是在 OSGi 中处理的方式。

相反,您的 showWeatherImpl 包可以使用 http 白板模式将自己作为 servlet 提供。这意味着它提供了实现 servlet 的服务。如果强制服务引用发生故障,Blueprint 将自动取消注册捆绑包的所有服务。

当然,如果您使用 showWeatherImpl 中的 bean 中的 java 代码将自己注册为 servlet,这当然无济于事。在这种情况下,您可以使用服务引用回调,它会在服务来去时通知您。

当然,就像 Grzegorz 提到的,声明式服务在默认情况下比蓝图更具动态性,并且可以更好地处理此类情况。

【讨论】:

  • AFAIK,如果强制服务引用失败,则对该实例的任何后续调用都将阻塞(因为您永远不会获得服务,而是服务的蓝图代理)并最终引发 ServiceUnavailableException。跨度>
  • 是的。那是真实的。因此,这仅在您拥有完整的服务链时才有效。 OSGi http 白板就是这样一个例子。在其他情况下,一旦您从外部接到 bean 的调用,而它的依赖项不可用,它就会阻塞。对我来说,这是我尽量只使用 DS 的原因之一。
猜你喜欢
  • 2012-03-12
  • 1970-01-01
  • 1970-01-01
  • 2023-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-25
  • 1970-01-01
相关资源
最近更新 更多