Попытка отследить сервис в пакете, развернутом на apache karaf. ServiceTracker#addingService не вызывается

Добавляю OSGI-сервис MyService в apache karaf примерно так:

  1. Создайте и аннотируйте сервис и его реализацию.
public interface MyService {//...}

@OsgiServiceProvider(classes=MyService .class)
@Singleton
public class MyServiceImpl implements MyService {//...}
  1. Используйте сборку maven с blueprint-maven-plugin и maven-bundle-plugin для обработки аннотаций. Объявление OSGi-сервиса и его реализация приводят к файлу bundle.jar!/OSGI-INF/blueprint/autowire.xml:
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
  xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0">
<bean id="myServiceImpl" class="com.foo.bar.MyServiceImpl"
  ext:field-injection="true" init-method="init">
    <property name="contextFactory" ref="initialContextFactory-"/>
</bean>
<service ref="myServiceImpl" interface="com.foo.bar.MyService"/>
</blueprint>

Этот XML известен пакету, поскольку он находится в MANIFEST.MF:

Bundle-Blueprint: OSGI-INF/blueprint/autowire.xml
  1. Скопируйте функцию, включая этот пакет, в karaf-home/deploy.

Теперь я хотел бы привязать эту службу к имени JNDI по соображениям совместимости. Я пытаюсь добиться этого, реализуя init() в MyServiceImpl и используя ServiceTracker:

@PostConstruct
public void init() {
    BundleContext context = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
    ServiceTracker tracker = new ServiceTracker(context, this.getClass(), null) {
        @Override
        public Object addingService(ServiceReference reference) {
            Object serviceObj = super.addingService(reference);
            try {
                Context c = new InitialContext();
                bind(c, "java:global/com.foo.bar.bundle/MyServiceImpl!com.foo.bar.MyService", serviceObj );
            }
            catch (NamingException e) { e.printStackTrace(); }
            return serviceObj;
       }
    };
    tracker.open();
}

private void bind(Context ctx, String name, Object value) { //... }

К сожалению, я получаю javax.naming.NotContextException, если выполняю поиск:

new InitialContext().lookup("java:global/com.foo.bar.bundle/MyServiceImpl!com.foo.bar.MyService");

Чтобы выяснить это, я сначала проверил, запущен ли пакет и добавлена ​​ли служба в консоли karaf:

karaf@root()> bundle:list | grep bundle
155 | Active   |  80 | 0.0.1.SNAPSHOT     | bundle
karaf@root()> bundle:services 155

bundle (155) provides:
----------------------
[com.foo.bar.MyService]

Затем я перезапустил karaf с параметром отладки и установил точку останова на init() и addedService(). Наблюдение показало: вызывается init(), поэтому ServiceTracker нужно правильно добавить в бандл. Но addingService() не звонят.

Что мне не хватает?


person Danny Lo    schedule 06.01.2016    source источник


Ответы (1)


В blueprint.xml вы публикуете сервис с его интерфейсом «com.foo.bar.MyService». Поэтому вам нужно использовать то же имя в поиске службы отслеживания.

Кстати. почему вы вообще используете ServiceTracker? Если вы публикуете службу из @PostConstruct вашего внедрения, просто опубликуйте его, используя:

Context c = new InitialContext();
bind(c, "java:global/com.foo.bar.bundle/MyServiceImpl!com.foo.bar.MyService", this );
person Christian Schneider    schedule 06.01.2016
comment
По какой-то причине я думал, что инициализированный bean-компонент и объект службы, который я получаю из пакета, будут двумя разными объектами. Удаление ServiceTracker, кажется, решает мою проблему, не могу быть уверенным на 100%, потому что теперь я получаю другие исключения. Просто для понимания, не могли бы вы объяснить, что вы подразумеваете под поиском в сервисном трекере? - person Danny Lo; 06.01.2016
comment
В этой строке вы настраиваете ServiceTracker для поиска службы с определенным именем класса new ServiceTracker(context, this.getClass(), null). Имя, которое вы там указываете, должно быть тем, с которым публикуется служба. Объекты this и сервис действительно разные. Blueprint регистрирует прокси для службы. Вам нужен этот прокси, если вы используете перехватчик, например, для JPA или транзакций. - person Christian Schneider; 06.01.2016
comment
Да, я действительно использую транзакции. Вероятно, поэтому я получаю сообщение об ошибке «Нужна активная координация». Я также нашел журнал где вы объясняете, почему выбрасывается это исключение :) Так что, похоже, мне действительно нужен ServiceTracker. - person Danny Lo; 06.01.2016
comment
Спасибо, что спасли мой день! Теперь я понимаю свою ошибку. Я публикую службу, а не ее реализацию, поэтому, конечно, мой ServiceTracker может только успешно ждать службы. - person Danny Lo; 06.01.2016
comment
В этом случае вы все равно можете избежать servicetracker. Просто создайте второй класс и внедрите в него bean-компонент blueprint с помощью аннотаций. В @PostConstruct второго класса вы можете безопасно опубликовать внедренный bean-компонент в jndi. - person Christian Schneider; 06.01.2016
comment
В чем преимущество второго класса по сравнению с сервисным трекером? - person Danny Lo; 07.01.2016
comment
Вам не нужна зависимость от API-интерфейсов OSGi, а код менее сложен. - person Christian Schneider; 07.01.2016