0

我正在创建一个包含大量捆绑包的应用程序。其中一些是接口,一些是这些接口的实现。我使用声明式服务 (DS) 来提供和使用服务,这意味着每个包都有一个 component.xml 描述我正在提供/引用的服务。

目前我有一个ClockWidget实现 3 个接口的类(如您在附图中所见)。对于实现的每个服务,我都有一个引用该服务的特定类。例如,Timeout该类具有接收任何实现该TimeoutListener服务的人的绑定方法。 在此处输入图像描述

问题是ClockWidget类的构造函数被调用了 3 次。显然,我将其与其他捆绑包使用的服务数量相关联。

问题是:为了处理实现多个服务的捆绑包,有什么好的方法/实践?我的意思是,我不希望这个捆绑包在应用程序中重复。我想在引用这个人的三个类中使用相同的实例。我尝试在清单中启用单例属性,但没有任何改变。

ClockWidget.class

public class ClockWidget implements Widget, TimeoutListener, DummyInterface {

    public ClockWidget() {
        System.out.println("ClockWidget constructor.");
    }

    @Override
    public String getWidgetName() {
        return "Clock widget";
    }

    @Override
    public void onTimeout() {
        System.out.println("Timeout!");
    }

    @Override
    public void dummyMethod() {
        // Does nothing.
    }
}

其组件定义ClockWidget.xml

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="test.e4.ClockWidget">
   <implementation class="test.e4.history.ClockWidget"/>
   <service>
      <provide interface="test.e4.widget.Widget"/>
      <provide interface="test.e4.timeoutlistener.TimeoutListener"/>
      <provide interface="test.e4.dummyinterface.DummyInterface"/>
   </service>
</scr:component>

使用由 提供的服务的类ClockWidget。在这种情况下,Timeout类:

public class Timeout {

    private ArrayList<TimeoutListener> listeners;

    public Timeout() {
        listeners = new ArrayList<>();
        startTimeoutTimer();
    }

    public void startTimeoutTimer() {
        long timeoutInMs = 60 * 1000;
        Timer timeoutTimer = new Timer();
        timeoutTimer.schedule(new TimerTask() {

            @Override
            public void run() {
                timeout();
            }
        }, timeoutInMs);
    }

    // Bind method from DS
    public void addListener(TimeoutListener listener) {
        listeners.add(listener);
    }

    // Unbind method from DS
    public void removeListener(TimeoutListener listener) {
        listeners.remove(listener);
    }

    public void timeout() {
        for (TimeoutListener listener : listeners) {
            listener.onTimeout();
        }
    }
}

超时组件说明:

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="test.e4.Timeout">
   <implementation class="test.e4.Timeout"/>
   <reference bind="addListener" cardinality="0..n" interface="test.e4.timeoutlistener.TimeoutListener" name="TimeoutListener" policy="dynamic" unbind="removeListener"/>
</scr:component>

有什么建议吗?

4

2 回答 2

2

ClockWidget 是在 3 个服务名称下注册的 DS 组件吗?或者 3 个 DS 组件,每个组件都注册在一个服务名称下。如果是后者,那么是的,ClockWidget 将为每个服务实例化一次,因为这就是 DS 所知道的。如果是前者,那么 ClockWidget 应该只实例化一次,因为它是在 3 个服务名称下提供的单个服务。

于 2014-05-28T16:07:24.043 回答
0

对不起,伙计们,我对你并不完全诚实。当然,我的系统要复杂得多。就像我的ClockWidget类有另一个在构造函数中被调用的方法。我不知道这可能会导致问题。这是完整的ClockWidget.class样子:

public class ClockWidget extends Widget implements TimeoutListener, DummyInterface {

    private ArrayList<ActivityListeners> activityListeners;

    public ClockWidget() {
        super();
        System.out.println("ClockWidget constructor.");
        lookupActivityListeners();
    }

    @Override
    public String getWidgetName() {
        return "Clock widget";
    }

    @Override
    public void onTimeout() {
        System.out.println("Timeout!");
    }

    @Override
    public void dummyMethod() {
        // Does nothing.
    }

    private void lookupActivityListeners() {

        activityListeners = new ArrayList<>();

        try {
            BundleContext context = FrameworkUtil.getBundle(this.getClass()).getBundleContext(); 
            Collection<ServiceReference<ActivityListener>> serviceReferences = context.getServiceReferences(ActivityListener.class, null);

            for (ServiceReference<ActivityListener> serviceReference : serviceReferences) {
                ActivityListener activityListener = (ActivityListener) context.getService(serviceReference);
                if (activityListener != null) {
                    activityListeners.add(activityListener);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

如您所见,该方法lookupActivityListeners搜索ActivityListener安装在 OSGi 中的所有 s 并将它们添加到数组列表中。我已经评论了这一行ActivityListener activityListener = (ActivityListener) context.getService(serviceReference);并且构造函数被调用了一次。

所以我不得不将lookupActivityListeners();调用更改为另一个地方而不是构造函数。现在一切都很好。但是,我仍然不知道为什么这会成为问题的根源。

无论如何,感谢您的回答。

于 2014-05-30T00:04:52.480 回答