2013-07-24 3 views
3

У меня есть традиционное корпоративное приложение Java, которое регистрирует кучу сервисов как Spring beans и регистрирует их с помощью JNDI. Я хотел бы преобразовать это, чтобы вместо этого использовать Spring с OSGi.Устранение экземпляра службы OSGi из статического метода

Ранее класс обслуживания был просто включен в пути к классам любого другого класса, который в ней нуждается, и имел статический метод ищет что-то вроде этого:

public class SomeService { 
    // private fields... 

    public static SomeService getInstance() { 
     SomeService svc = null; 
     try { 
      InitialContext ctx = new InitialContext(); 
      svc = (SomeService)ctx.lookup("java:/SomeService"); 
     } catch (NamingException ex) { 
      logger.info("Exception in getNamedObject", ex); 
     } 
     return svc; 
    } 

    // Setters and getters, some of which are filled-in with Spring beans 

    // Other methods etc... 
} 

Везде, где используется служба, у нас есть такой код это:

SomeService svc = SomeService.getInstance(); 
// or even 
SomeObject results = SomeService.getInstance().getSomeObject(); 

Теперь я понимаю, «правильный» способ преобразовать это было бы удалить getInstance() полностью и заставить всех пользователей интерфейс, чтобы иметь свои собственные ссылки на реализацию, поставляемой весной и сконфигурированной в xml-файлы в M ETA-INF. Однако это изменение было бы слишком большим, чтобы сделать все сразу, поскольку система уже находится в производстве).

Есть ли способ получить экземпляр службы OSGi, аналогичный приведенному выше подходу JNDI?

Обновление: некоторые разъяснения
Просто быть очень ясно, на моих целей здесь - я знаю, что это не очень хороший подход в целом. Это, однако, крупное корпоративное приложение, которое находится в производстве, и изменение всего в одном направлении, чтобы приспособиться к «идеальной» структуре OSGi, - просто слишком большое изменение, чтобы сделать все сразу.

То, что я пытаюсь сделать здесь, состоит в том, чтобы вырвать небольшую часть приложения и сделать его готовым к использованию в качестве отдельного пакета OSGi. Но так как остальная часть приложения - «код клиента», если вы еще не готовы к этому изменению, у меня должен быть промежуточный шаг, который позволяет мне использовать этот код как по-старому, , так и as служба OSGi. Со временем остальная часть appilcation также будет модульной и OSGi-ified, и в конечном итоге эти статические заводские методы будут полностью удалены.

До тех пор, однако, отмечает, что «это неправильный способ сделать OSGi» не очень полезно для меня - я знаю, что это не так, но это даже не моя окончательная форма ...

ответ

5

Вы пытаетесь вытолкнуть квадратный штифт через круглое отверстие. Каждый разработчик учится в информатике 101 о том, что глобальные переменные являются плохими, поэтому я бы сказал, что цитаты вокруг «правильные» очень неуместны, поскольку статика является первичными глобальными переменными.

Поскольку OSGi никогда не полагалась на глобальные переменные (статика в Java), вы можете запускать OSGi в OSGi в OSGi в файле WAR на сервере приложений, работающем поверх OSGi. Статика зла (сначала говорят Ансельм Байрд, автор ServiceSpace, предшественник OSGi). Модель обслуживания была разработана для решения проблемы, с которой вы столкнулись; любая реализация услуг может ссылаться на другую услугу, его интерфейс и/или свойств из любой точки:

@Reference 
void setSomeService(SomeService s) { 
    this.s = s; 
    ... 
} 

В модульной системе, центральный Бог XML является анафемой.

Нет проблем с вашей проблемой, так как вы неизбежно столкнетесь с проблемами при заказе. В OSGi услуга не гарантируется быть доступной (одна из ее самых мощных и неправильно понятых функций). Ваш провайдер услуг может бесплатно приходить и уходить в любое время. Поскольку ваша статическая модель не обрабатывает зависимости, она будет ложно терпеть неудачу, потому что она предполагает неявное упорядочение.Теперь многие люди делают эти статические решения, потому что они обычно работают большую часть времени; Я думаю, что «большую часть времени», однако, не должно быть достаточно хорошим для компьютерного программного обеспечения. Не думайте, что мы это сделаем, если мы будем нести ответственность за наши продукты ...

Предполагая, что вы работаете с Eclipse или другой IDE с рефакторингом, я с трудом понимаю, почему было бы трудно изменить базу кода, чтобы ввести эту услугу?

OSGi - это не временная диета и не волшебный соус, как большинство библиотек Java, это зрелая система модульности, которая требует, чтобы ваше приложение стало действительно модульным, т. Е. Это изменение образа жизни. Попытка использовать структуру, но затем идти против ее потока - это стратегия, которая приводит к большому сожалению в моем опыте.

+0

В конце концов мы перенесем весь код, чтобы ввести услугу, но на данный момент это не вариант - не потому, что было бы сложно переписать код, а потому, что было бы невозможно развернуть код в производство в непротиворечивое будущее, так как для этого требуется перезапуск систем, которые невозможно отключить по своему усмотрению. Если я могу найти промежуточное решение, в котором служба экспортируется как служба osgi, но при этом позволяет использовать старый способ доступа к ней, мы можем перезаписать эту часть системы, развернуть пакет услуг и внести изменения в другие места, когда возможное. –

+0

Кроме того, в отношении статики: нет фактического требования о том, что 'getInstance()' возвращает * тот же * экземпляр каждый раз - просто что API для получения * a * экземпляра службы не изменился. –

+2

Но вы можете справиться с тем, что нет экземпляра. Про -1 вы можете раздражать то, что мир не работает, как вы думаете, что нужно, но стрельба по посланнику - это нечто противоположное. –

0

Я думаю, что нашел способ сделать это - я работаю над его тестированием, но из документации этот подход кажется многообещающим.

Я создал класс resolver, который отвечает за фактическую выборку сервиса из OSGi, и который делает это посредством реализации BundleContextAware. Таким образом, я надеюсь на BundleContext будет впрыскивается, из которого я могу схватить экземпляр службы:

public class SomeServiceResolver implements BundleContextAware { 
    private BundleContext _cxt; 

    @Override 
    public void setBundleContext(BundleContext context) { 
     _cxt = context; 
    } 

    public SomeService resolveService() { 
     // TODO: Add error handling if service isn't available 
     ServiceReference<SomeService> svcref = _ctx.getServiceReference(SomeService.class); 
     SomeService svc = _ctx.getService(svcref); 
     return svc; 
    } 
} 

Затем статический метод getInstance() становится просто

public static SomeService getInstance() { 
    return new SomeServiceResolver().resolveService(); 
} 

Как я уже сказал, я не имею испытал это еще, так что мы посмотрим, действительно ли это работает.

+1

Итак, вы получаете услуги, но не убираете их? –

+0

@NeilBartlett: Нет, на данный момент я этого не делаю - и учитывая текущее состояние этого приложения, я не уверен, что я могу, так как не знаю, когда клиентский код выполняется с помощью службы пример. Я буду изучать это, хотя, когда у меня есть работа, работающая. –

+0

Не уверен, что это может сработать. Вы инициализируете свой SomeServiceResolver, используя новый. В этом случае у весны не будет возможности ввести контекст связки в нее. –

2

В любом случае вы хотите опубликовать свое обслуживание в качестве службы OSGi. Вопрос только в том, как получить доступ к нему с минимальным воздействием на ваш клиентский код.

Один Подход может быть использование:

FrameworkUtil.getBundle (YourClass) .getBundleContext(); Это позволяет получить доступ к контексту связки в статических методах. Оттуда вы можете получить доступ к сервису.

Другой подход может заключаться в использовании aries jndi. Он позволяет извлекать службы OSGi с помощью jndi. Поэтому это также должно помочь.

Конечно, как указано Петром, это должно быть временным решением.

+0

Овен JNDI определенно звучит как хороший способ пойти. Я должен буду изучить это ... –

Смежные вопросы