В этой статье, состоящей из двух частей, , технический директор PBT Group , консалтинговой компании по программному обеспечению, базирующейся в Южной Африке, знакомит вас с OSGi и обсуждает ее актуальность именно в контексте предприятия. Какова точная проблемная область OSGi в этой области? В этой первой части он использует фрагменты кода, чтобы показать, как можно решать проблемы, связанные с динамическим управлением классами. — Гертьян Виленга, лидер зоны JavaLobby
OSGi — Динамическая модульная система для Java в последнее время привлекает к себе немало внимания. Учитывая, что такие высокопрофильные продукты, как Eclipse, IBM WebSphere, JOnAS, Spring Framework, все используют OSGi или предоставляют поддержку OSGi, это неудивительно. Что удивительно, так это то, что OSGi в настоящее время находится в четвертой версии, что подразумевает значительную степень зрелости. Еще более удивительным является то, что OSGi изначально предназначалась для небольших встраиваемых устройств, работающих под управлением Java. Так почему же мы обращаем внимание на технологию (на самом деле, это просто спецификация), которая изначально была предназначена для решения проблем на противоположном конце континуума от корпоративных приложений?
В области корпоративных приложений в течение длительного времени мы решали типичные корпоративные проблемы, такие как масштабируемость, управление транзакциями, безопасность, высокая доступность, управляемость и тому подобное. Возможно, это стереотипное утверждение, но мы понимаем эти проблемы и успешно разработали решения для каждой из них в приемлемой степени. OSGi не предназначена для решения таких проблем, и эти проблемы не обсуждаются в этой статье.
Однако более сложными являются более абстрактные проблемы, с которыми мы сталкиваемся при разработке и создании корпоративных приложений. Для многих из этих абстрактных проблем у нас есть абстрактные решения, то есть шаблоны. Интересно, что эти абстрактные проблемы связаны не столько с корпоративными приложениями, сколько с архитектурой программного обеспечения, объектной ориентацией и общими проблемами разработки программного обеспечения. Действительно, у нас есть много шаблонов для многих проблем, но у нас также есть проблемы, которые не имеют решений на основе шаблонов.
OSGi приобрел известность, потому что он используется для решения некоторых сложных проблем в разработке корпоративных приложений Java и в целом в архитектуре программного обеспечения. Есть несколько проблем, которые можно решить с помощью OSGi.
- Первая проблема заключается в минимизации времени простоя и улучшении процедур отката в новых выпусках программного обеспечения. В этой проблеме трудная часть заключается не во введении новой версии, а скорее в удалении более старой версии, обеспечивая при этом непрерывную работу системы. Все дело в динамическом управлении. Это также приводит к следующей проблеме.
- Управление версиями Java-классов или JAR-файлов практически отсутствует. Отсутствие контроля версий затрудняет управление обратной совместимостью. Сочетание динамического управления классами OSGi и управления версиями классов обеспечивает элегантное управление во время выполнения обеих этих проблем.
- Наконец, эффективное разбиение приложений на модули в значительной степени не решено. Это особенно проблематично с Java, потому что его слабый загрузчик классов создал ад classpath (или ад JAR, который ничем не отличается от DLL-ад на Win32).
Эти проблемы, конечно, не единственные проблемы, которые в значительной степени не решены, и при этом они не являются единственными проблемами, решаемыми OSGi. Тем не менее, для крупномасштабных корпоративных приложений, которые имеют долгоживущие проекты, это, безусловно, занимает важное место в повестке дня любого архитектора программного обеспечения (или вскоре поднимется вверх по списку приоритетов). Давайте посмотрим на каждый из этих трех по очереди.
Динамическое Управление Классами
Продуктивность разработки на основе POJO в последнее время широко рекламируется. Популярный Spring Framework, объектно-реляционный картограф Hibernate и другие проекты с открытым исходным кодом доказали, что разработка на основе POJO может уменьшить сложность и простоту. Spring Framework с контейнером Inversion of Control / Dependency Injection также показал, что разработка на основе интерфейса приводит к хорошему разделению проблем и слабой связи.
Конечно, разработка на основе интерфейса и парадигма разработки на основе POJO очень продуктивны. Однако, как только эти приложения, основанные на POJO, развернуты в JVM, их управление во время выполнения становится мало. Написание или генерация JMX MBeans действительно предлагает некоторую
форму управления, но отсутствует управляемая экосистема, аналогичная экосистеме EJB.
Благодаря OSGi решения на основе POJO наконец-то имеют управляемую экосистему; и экосистема OSGi является динамичной. Пакеты (т. Е. Пакеты в терминологии OSGi) могут динамически загружаться и выгружаться во время выполнения, при этом абсолютно не требуется отказов JVM или среды выполнения OSGi. Для этого загрузчик класса OSGi действительно прочный и водонепроницаемый. Никакие странные хитрости загрузки классов не допускаются, и даже отражение не может заглянуть внутрь связок.
Что еще более важно, OSGi R4 представляет реестр служб, в котором пакеты регистрируют интерфейсы, которые они хотят предоставить (то есть экспортировать) всем остальным в среде выполнения. Любой другой пакет может выполнить поиск в реестре, чтобы найти необходимые интерфейсы. Рассмотрим следующие фрагменты кода, которые регистрируют класс обслуживания, который находит класс объекта доступа к данным, который ему необходим для выполнения своих задач.
- Определите интерфейс сервиса:
package org.samples.service;
import java.util.List;
public interface MyService {
public List findAllObjects();
} - Определите интерфейс доступа к данным:
package org.samples.dao;
import java.util.List;
public interface MyDao {
public List retrieveAllObjects();
} - Реализуйте интерфейс объекта доступа к данным:
package org.samples.dao;
// ...
public class MyDaoImpl implements MyDao {
// ...
public List retrieveAllObjects() {
// ...
return objectList;
}
} - Класс DAO регистрируется в реестре службы OSGi с использованием активатора для пакета, который содержит DAO:
package org.samples.dao;
// ...
public class MyDaoActivator implements BundleActivator {
private ServiceRegistration registration;
public void start(BundleContext context) { MyDao dao = new MyDaoImpl(); Dictionary props = new Properties(); // ... registration = context.registerService(MyDao.class.getName(), dao, props);
}
public void stop(BundleContext context) {
registration.unregister();
}
} - Реализуйте интерфейс службы, который использует реализацию DAO:
package org.samples.service;
// ...
public class MyServiceImpl implements MyService {
private MyDao myDao; protected void bindDao(MyDao dao) { myDao = dao; } protected void unbindDao(MyDao dao) { myDao = null; } public List findAllObjects() { // ... return (myDao == null) ? null : myDao.retrieveAllObjects(); }
} - Создайте класс, который будет отслеживать DAO в реестре службы OSGi. Этот класс отслеживает количество раз, когда DAO был связан с классом Service, и очищает регистр службы во время отмены привязки, если количество использований падает до нуля. Кроме того, метод добавлениеService () регистрирует MyService в реестре службы OSGi:
package org.samples.dao;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.util.tracker.ServiceTracker;
// ...
public class MyDaoTracker extends ServiceTracker {
private final MyServiceImpl myService = new MyServiceImpl();
private int daoCount = 0;
private ServiceRegistration registration = null;
public MyDaoTracker(BundleContext context) {
super(context, MyDao.class.getName(), null);
}
private boolean registering = false;
public Object addingService(ServiceReference reference) {
MyDao myDao = (MyDao) context.getService(reference);
myService.bindDao(myDao);
synchronized (this) {
daoCount++;
if (registering)
return myDao;
registering = (daoCount == 1);
if (!registering)
return myDao;
}
ServiceRegistration reg = context.registerService(MyService.class
.getName(), myService, null);
synchronized (this) {
registering = false;
registration = reg;
}
return myDao;
}
public void removedService(ServiceReference reference, Object service) {
MyDao myDao = (MyDao) service;
myService.unbindDao(myDao);
context.ungetService(reference);
ServiceRegistration needsUnregistration = null;
synchronized (this) {
daoCount--;
if (daoCount == 0) {
needsUnregistration = registration;
registration = null;
}
}
if (needsUnregistration != null) {
needsUnregistration.unregister();
}
}
} - Наконец, создайте активатор Bundle для класса MyService, который загружает средство отслеживания службы DAO, которое, в свою очередь, отслеживает привязки DAO к службе:
package org.samples.service;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
// ...
public class MyServiceActivator implements BundleActivator {
private MyDaoTracker tracker;
public void start(BundleContext context) {
tracker = new MyDaoTracker(context);
tracker.open();
}
public void stop(BundleContext context) {
tracker.close();
}
}Помимо специального кода OSGi для Bundle Activators и сервис-трекеров, остальная часть кода основана на интерфейсе и стиле разработки на основе POJO.
Проект Spring Dynamic Modules устраняет необходимость написания приведенного выше стандартного кода для регистрации сервисов, поиска сервисов и сервисов отслеживания. Тот же самый пример выше легко соединяется в дескрипторе контекста приложения Spring Framework.
- Следующий фрагмент использует схему bean-компонентов Spring Framework по умолчанию и схему osgi Spring Framework для конкретных bean-компонентов OSGi. Обратите внимание на согласованность стиля, который преобладает в Spring Framework для описания внедрения зависимостей:
Загрузка и выгрузка этих пакетов абсолютно тривиальна. В реализациях OSGi с открытым исходным кодом, таких как Apache Felix и Eclipse Equinox, доступна текстовая консоль для управления средой.
Понятно, что OSGi — это среда, в которой зависимости появляются и исчезают без предупреждения. Что вы делаете, когда ваши зависимости отсутствуют или исчезают, зависит от вас. Очевидные варианты — игнорировать отсутствующие зависимости, подождать их или вызвать исключение.
Другой поворот заключается в том, что может существовать более одного сервиса, который удовлетворяет зависимостям пакета. Поэтому кардинальность зависимостей значительна. Способ, которым можно решить кардинальность, выходит за рамки этой статьи.
На следующей неделе: в заключительной части этой серии из двух частей Аслам обсуждает классное управление версиями и модульность. Как управление версиями класса связано с обратной совместимостью? Как модули могут обнаружить друг друга? Аслам рассказывает нам о Domain Driven Design и в заключение отвечает на вопрос «Можете ли вы использовать OSGi в своих приложениях сегодня?» Для ответа на этот вопрос прочитайте часть 2, на этот раз на следующей неделе …