Пакет создается более одного раза с использованием DS
Я создаю приложение, у которого есть бедра связок. Некоторые из них являются интерфейсами, а некоторые являются реализацией этих интерфейсов. Я использую декларативные сервисы (DS) для предоставления и использования сервисов, что означает, что в каждом пакете есть файл component.xml, описывающий сервис (ы), которые я предоставляю / на которые ссылаюсь.
В настоящее время у меня есть класс под названием ClockWidget
который реализует 3 интерфейса (как вы можете видеть на прилагаемой диаграмме). Для каждого реализованного сервиса у меня есть определенный класс, который ссылается на этот сервис. Например, Timeout
класс имеет методы привязки, которые получает любой, кто реализует TimeoutListener
оказание услуг.
Проблема в том, что конструктор ClockWidget
класс вызывается три раза. Очевидно, я связал это с количеством сервисов, которые используются другими пакетами.
Вопрос в том, что является хорошим подходом / практикой для того, чтобы иметь дело с пакетами, которые реализуют более одного сервиса? Я имею в виду, я не хочу, чтобы этот пакет дублировался в приложении. Я хотел бы использовать один и тот же экземпляр в трех классах, которые ссылаются на этого парня. Я попытался включить свойство singleton в манифесте, но ничего не изменилось.
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>
Любое предложение?
2 ответа
Извините, ребята, я не был полностью честен с вами. Конечно, моя система намного сложнее. Это как мой 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
s устанавливается в OSGi и добавляет их в список массивов. Я прокомментировал строку ActivityListener activityListener = (ActivityListener) context.getService(serviceReference);
и конструктор был вызван один раз.
Поэтому я должен был изменить lookupActivityListeners();
звонить в другое место вместо конструктора. Сейчас все в порядке. Тем не менее, я до сих пор не знаю, почему это будет источником проблемы.
В любом случае, спасибо за ответы.
ClockWidget один компонент DS зарегистрирован под 3 именами служб? Или 3 компонента DS, каждый из которых зарегистрирован под одним именем службы. Если последнее, то да, ClockWidget будет создан один раз для каждой службы, поскольку это все, что DS знает. Если первое, то ClockWidget должен создаваться только один раз, поскольку это единственный сервис, доступный под 3 именами сервисов.