`

用 Eclipse 构建轻量级的 OSGi 应用程序

 
阅读更多

简介: OSGi 一直是在 Java™ 领域及诸多其他领域中构建动态模块系统的实际行业标准。本文通过一系列相关示例展示在 Eclipse 中开发 OSGi 应用程序的过程、场景、解决方案和实践。深入阅读本文以系统了解 OSGi 框架与核心服务。

 

简介

构建模块化系统的需求非常多。在 Java 领域及诸多其他领域中,开放服务网关协议 (Open Services Gateway initiative, OSGi) 一直都被视为一种成熟的模块化系统框架,它一般包括桌面应用程序、Web 应用程序、移动应用程序,以及中间件。OSGi 提供了一种底层的基础设施,可用来开发具有模块化、动态性的面向服务应用程序。其大多数特性和功能均通过 OSGi 规范和实现中的服务所定义和提供的。在了解几个核心 OSGi 服务的概念和用法后,我们就能够利用这些服务以及 Eclipse IDE 构建轻量级模块化应用程序来满足复杂的需求。

一个样例应用程序

该样例应用程序是一个数据收集器,可从不同的数据源检索数据并将这些数据解析成统一的预定义的数据格式以供进一步处理。有多个系统具有不同的 数据格式定义和检索方法。一般情况下,应用程序生产者或拥有者常常都期待第三方供应商基于此应用程序发布的 API 为特定的数据源实现业务逻辑。理想情况下,数据收集器客户端应集成第三方代码,并且可以直接运行而无需对现有代码、配置或部署结构进行任何更改。这是构建 模块化系统的一个典型要求,稍后我们将介绍如何使用 OSGi 核心服务来实现这一点。

为了充分发挥 OSGi 的强大功能,对应用程序的架构进行细致的设计非常必要,虽然设计并不是很复杂。讨论 OSGi 应用程序设计原则的文章有很多,我建议您参阅这些文章(请参阅 参考资料)。

图 1 显示了该样例数据收集器应用程序的基础架构。该应用程序由三种 bundle 组成:数据收集器框架 bundle、文本解析器 bundle 和收集器 bundle。


图 1. 样例数据收集器应用程序的基础架构 
此图显示了该数据收集器框架 Bundle 如何具备了面向文本解析、数据收集器和配置向导的 API,并可与各种收集器和文本解析 bundle 进行交互 

框架 bundle 充当整个应用程序的核心组件。它可以是一个 bundle(提供了面向其他 bundle 的收集器和向导 UI API),也可以是一个客户端(使用来自其他功能性 bundle 的服务)。通过将 API 和客户端 bundle 并入到一个 bundle,第三方数据收集器开发人员就可以将最少数量的 bundle jar 导入到其 IDE 来实现 API,然后再在 Eclipse 中运行并测试整个应用程序。收集器 bundle 提供了数据收集服务和向导页服务。另一方面,收集器 bundle 还能充当一个客户端,调用由框架 bundle 提供的文本解析器 API,而单独的解析器 bundle 将为之提供服务。

所有这些 bundle 都会通过 OSGi 核心服务松散地进行相互藕合和交互。因此,除了框架 bundle 之外的所有 bundle 都能很容易地被添加、删除、暂停或升级,即便是应用程序部署之后,仍能如此。这对于自动化的软件交付过程非常重要。

接下来,我们将展示实现并部署一款小型而又完整的 OSGi 应用程序的过程和实践。

 

定义 OSGi 项目布局

我们需要在 Eclipse 中为每个 bundle 创建一个新的插件项目。如下假设您已经具备了在 Eclipse 中创建 OSGi 的经验和知识。此外,还要确保下载了 Eclipse IDE 的最新发布版以及单独的 Equinox SDK。建议使用 Eclipse 3.4 或更高版本。

正如 图 1 所描述的,需要至少三个 bundle 项目,框架 bundle、文本解析器 bundle 和数据收集器 bundle。定义项目的布局(比如包和文件夹等级结构设计)非常重要。让我们以 图 2 所示的这个框架 bundle 为例。


图 2. 样例项目布局 
屏幕截图显示了一个典型项目的目录结构 

创建 OSGI-INF 文件夹来存储该 bundle 中所有的 OSGi 组件定义文件(组件概念将稍后介绍)。根据功能类别创建各个包。我们需要在早期阶段计划其他 bundle 可见的包以避免 bundle 之间的严重耦合。在该样例框架 bundle 中,会导出下列两个包。

  • dw.sample.dc.api:包含了要实现的所有 API。
  • dw.sample.dc.consts:包含 bundle 之间共享的常数和枚举,比如事件参数。

使用 OSGi Declarative Services 注入服务

模块化 和面向服务 是 OSGi 规范中的两个关键概念。公开实现类虽受 OSGi 框架支持,但是并不推荐使用。相反,从编程角度来看,bundle 应能够通过发布和消费服务 或类实例 来进行相互交互。OSGi 提供了两个方法来实现此目标。

  • 通过 OSGi 服务层提供的 BundleContext 在服务注册表中注册和检索服务。
  • 利用 OSGi R4 规范内的 Declarative Services。

Declarative Services (DS) 声明了组件模型的概念。一个组件就是由组件定义文件定义的一个 Java 对象,用来提供服务以及检索所引用的服务。

组件的生命周期是由此 OSGi 容器管理。而且,所引用的服务实例可动态注入到组件。DS 可处理服务查找、以及根据预定义的策略将服务与组件进行绑定或解除绑定。因此,开发人员能够使用简洁的代码生成一个高度动态的系统。

创建第一个服务组件

让我们从一个简单的用例开始:数据收集器框架 bundle 定义了一个文本解析器 API,文本解析器 bundle 提供默认的解析器服务。

在框架 bundle 中,服务 API 在所导入的 dw.sample.dc.api 包中进行定义。参见 清单 1


清单 1. 文本解析器 API 
				
public interface ITextParser {
public String parseText(String input);
}

在文本解析器 bundle 项目中, 首先,必须将 dw.sample.dc.api 包导入到此 manifest 来确保这个接口类可由当前的 bundle 类加载程序进行加载。其次,创建一个类来实现上述接口。

最后,也是最为重要的一步是,将实现类定义为一个组件,这就需要创建一个组件定义文件并在 bundle manifest 中注册它。为了简化该过程,我们使用 Eclipse 提供的向导(老版本可能没有):

  1. 右键单击此解析器 bundle 中的 OSGI-INF 文件夹并选择 New>Component Definition
  2. 将刚刚创建的这个实现类文件指定为组件类,再指定定义文件名称和组件名称,然后单击 Finish
  3. 在图形组件定义配置窗口中,切换到 Services 选项卡并将此框架 bundle 的服务接口类指定为这个组件所提供的服务。参见如下 图 3 所示。

图 3. 指定所提供的服务 
这个屏幕快照显示了将所提供的服务配置为 dw.sample.dc.api.ITextParser 

这时,向导会生成一个新的 textParserComponent.xml 并将这个组件注册到 bundle manifest,如清单 2 所示。


清单 2. 新生成的组件配置 
				
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
  name="dw.sample.textparser.defaultparser">
   <implementation class="dw.sample.textparser.service.DataCollectorDefaultTextParser"/>
   <service>
      <provide interface="dw.sample.dc.api.ITextParser"/>
   </service>
</scr:component>

MANIFEST.MF
...
Service-Component: OSGI-INF/textParserComponent.xml

现在,我们实现了一个简单而又完整的组件,当某客户端调用框架 bundle 中的 API 时,该组件将能在运行时提供服务。

接下来,我们将展示一个更复杂的组件并介绍如何使用其他组件的服务。

一个较高级的用例

让我们考虑这样一个场景:用户要能通过 GUI 与数据收集器应用程序进行交互,这就意味着用户要能够在一系列向导页的指导下输入所需数据。然后再启动收集的过程并观察此 UI 上的进程。显然,框架并不知道第三方数据收集器需要什么数据。为了满足这一需求,数据收集器 bundle 需要提供至少一个配置向导页。此外,还需要此框架在应用程序部署到用户环境后能够无缝和动态地集成和提供所有的第三方向导。听起来很酷,是不是?那么就让 我们来看看如何利用 OSGi Declarative Services 的强大功能来实现这个目的(参见 图 4)。


图 4. 动态的向导顺序 
此图显示了如何从向导群组 1 如何进入向导群组 2,后者又如何进入到向导 4。向导 3 已被灰色屏蔽。 

与之前的用例类似,需要定义一个 API。对于本例而言,我们需要仔细设计接口以避免在确保此 API 能够满足来自数据收集器端的关键功能需求的同时增加向导系统的复杂度。因此,这个 API 的设计需要至少满足如下几点:

  • 不允许来自不同数据收集器的向导服务之间有任何的通信和依赖性,但不限制同一数据收集器的向导服务间的通信和依赖性。
  • 在用户步出数据收集器的最后一个向导页时保存用户此阶段的输入。

这是本例中最为重要的一步。一个结构良好的 API 设计在于能够提供清晰的界面而又同时能保持服务的高度内聚,而并不在乎实现中的逻辑和代码的复杂性。

SWT 和 JFace 被用作此应用程序向导及其他 GUI 组件的底层库。如果我们计划在这个两个库中跨多个包使用资源和类,只需将它们作为所需的 bundle 添加到框架 bundle 和数据收集器 bundle 的 manifest 文件。此外,还需要导入 org.osgi.service.component 包,因为我们稍后会调用这个包中的类。

框架 bundle 中所定义的这个向导 API 由两个类组成,如 清单 3 所示。


清单 3. 定义向导服务 API 
				
public interface ICollectorWizardGenerator {
public List<CollectorWizardPage> getWizardSequence();
public int getWizardPositionIndex();
}

---
/**
 * Inherit the jface WizardPage by adding two customized methods
 */
public abstract class CollectorWizardPage extends WizardPage {
    …
/**
* Trigger the customized logic when the next button on the wizard is
 * pressed
 * 
 * _cnnew1@return whether to jump to next page.
 */
public abstract boolean nextPressedTrigger();

/**
* Save user input in the current wizard.
 */
public abstract void saveWizardInput();    
}

在数据收集器 bundle 中,实现此向导 API 并将实现 ICollectorWizardGenerator 接口的类定义为服务组件(参见 清单 4)。


清单 4. 向导服务组件 
				
public class ProfileWizardGeneratorImpl implements ICollectorWizardGenerator {
    private int wizardPosition = 10;

    protected void activate(ComponentContext context) {
        try {
            wizardPosition = ((Integer) context.getProperties().get(
                    "wizardPosition")).intValue();
        } catch (NumberFormatException e) {
            wizardPosition = 10;
        }
    }
    public List<CollectorWizardPage> getWizardSequence() {
        List<CollectorWizardPage> wizardPageSeq = new ArrayList<CollectorWizardPage>();
        wizardPageSeq.add(new ProfileCollectorWizardPage1());
        wizardPageSeq.add(new ProfileCollectorWizardPage2());
        return wizardPageSeq;
    }
    public int getWizardPositionIndex() {
        return wizardPosition;
    }
}

---
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" 
  name="dw.sample.dc.profile.wizardgenerator">
   <implementation class="dw.sample.dc.profile.service.ProfileWizardGeneratorImpl"/>   
   <service>
      <provide interface="dw.sample.dc.api.ICollectorWizardGenerator"/>
   </service>
   <property name="wizardPosition" type="Integer" value="2"/>
</scr:component>

注意,此组件类中的 activate 方法被覆盖了。这个方法以及 deactivate 方法是在激活和去激活组件时由 OSGi 框架所调用的方法。将 ComponentContext 对象传递至 activate 方法以便我们能获得诸如 XML 文件中定义的组件属性的组件相关信息。在这里,数据收集器供应商可以定义向导的位置索引以便框架 bundle 可以相应地按排向导出现顺序。

至此,我们已经制作了两个组件作为服务提供者。

使用服务

在 Declarative Services 模型中,服务被动态地注入到组件中。下列 清单 5 中的代码展示了如何在 bundle 中引用和使用它们。


清单 5. 解析器服务加载器组件 
				
public class TextParserLoader {
    private static TextParserLoader instance;
    ... ...
    private ITextParser parser;

    public static TextParserLoader getInstance() {
        return instance;
    }
    protected void activate(ComponentContext context) {
        try {
            locker.lock();
            instance = this;
        } finally {
            locker.unlock();
        }
    }
    public void setTextParser(ITextParser parser) {
        this.parser = parser;
    }
    public void unsetTextParser(ITextParser parser) {
        if (this.parser != parser) {
            return;
        }
        this.parser = null;
    }
    public ITextParser getTextParser() {
        return parser;
    }
}

---
<implementation class="dw.sample.dc.profile.service.TextParserLoader"/>
<reference bind="setTextParser" cardinality="1..1" 
  interface="dw.sample.dc.api.ITextParser" name="ITextParser" 
policy="dynamic" unbind="unsetTextParser"/>

在这里,我们在这个组件类中应用了 singleton 模式。此 bundle 中的其他非组件对象能获取和使用来自这个惟一的 TextParserLoader 实例的服务,同时又能摆脱掉特定于 OSGi 的代码。该加载器类的功能有些类似于传统 Java 应用程序中的 factory 类,但惊人之处是它不需要执行任何繁琐的类加载、反射和实例初始化的操作。

DS 支持此组件 XML 文件中定义的各种服务引用策略:

  • Policy:policy 属性具有两个值,即静态和动态。默认为静态策略,表明只要所引用的服务有任何变更,组件都将被重新激活。相反,动态策略则只调用预定义的绑定和去绑定方法,所以更受推荐。
  • Cardinality:这个属性具有四个可用值:1..1、1..n、0..1 和 0..n。考虑到同一个 API 可能会有多个服务可用,结尾的数字指明是否所有的服务或者只有其中的一个服务将注入到此组件中,而开始数字则指明是否强制可用服务来激活此组件。

基数 1..1 是默认值,我们从上面的示例中已经了解到了它是如何使用的。对于 0..n 的情况,它也可以与此 singleton 模型一起得到很好的处理,如 清单 6 所示。


清单 6. 注入多个服务 
				
public class DataCollectorWizardSequence {
    ...
    private List<ICollectorWizardGenerator> wizardGeneratorSeq = 
	                            new ArrayList<ICollectorWizardGenerator>();
    ...
    public void addCollectorWizardGenerator(ICollectorWizardGenerator wizardGenerator) {
        wizardGeneratorSeq.add(wizardGenerator);        
    }
    public void removeCollectorWizardGenerator(ICollectorWizardGenerator wizardGenerator)
    {        
        wizardGeneratorSeq.remove(wizardGenerator);        
    }
    public List<CollectorWizardPage> getDataCollectorWizardSequence() {
        List<CollectorWizardPage> collectorWizardSequence = 
		                    new ArrayList<CollectorWizardPage>();
        try {
            locker.lock();
            /*
             * Arrange the wizard sequence according to position indexes 
	    * defined by each wizard services
	    */
            Collections.sort(wizardGeneratorSeq,
                    new CollectorWizardSequenceComparator());
            for (ICollectorWizardGenerator generator : wizardGeneratorSeq) {
                collectorWizardSequence.addAll(generator.getWizardSequence());
            }
            return collectorWizardSequence;
        }
        finally {
            locker.unlock();
        }
    }
}

---
<reference bind="addCollectorWizardGenerator" cardinality="0..n" 
       interface="dw.sample.dc.api.ICollectorWizardGenerator" 
	   name="ICollectorWizardGenerator" policy="dynamic" 
	   unbind="removeCollectorWizardGenerator"/>

在理解了如何利用引入到 Declarative Services 中的组件来发布和使用服务后,接下来我们将来看看如何有效地利用其他的 OSGi 核心服务。

 

 

用 Configuration Admin Service 管理 bundle 配置

Configuration Admin Service 为 OSGi 应用程序提供了一种统一的方式来管理本地或远端的配置数据,可以是服务级别,也可以是 bundle 级别。我们将以一个最为常见的用例开始,即本地存储、检索和更新 bundle 配置数据。

首先,检查 Eclipse plugins 文件夹中是否存在 org.eclipse.equinox.cm_<version>.jar,它是 OSGi Configuration Admin Service 的 Equinox 实现。如果没有的话,单独下载 Equinox SDK 并将其放至该文件夹中。然后,将 org.eclipse.equinox.cm 包导入到目标 bundle manifest。

要使用 Configuration Admin Service,首先,也是最重要的是必须实现并发布此 ManagedServiceAPI 作为目标 bundle 的服务。只要实现 updated 方法即可。不同的 ManagedServices 是由随服务注册的 SERVICE_PID 来区别的,因此对其配置进行更改时,就会触发相应的服务。为了管理 bundle 级别的配置,清单 7 中的 bundle 激活器将是一个能提供 ManagedService 的合适对象。


清单 7. 提供 ManagedService 的 bundle 激活器 
				
public class Activator implements BundleActivator {
    private ServiceRegistration cmSvrReg;

    public void start(BundleContext context) throws Exception {
cmSvrReg = context.registerService(ManagedService.class.getName(),
                    this, initMgrServiceProp());
}
    public void stop(BundleContext context) throws Exception {
        cmSvrReg.unregister();
    }
    public void updated(Dictionary properties) throws ConfigurationException {
        if (cmSvrReg == null) {
            return;
        }
        if (properties == null) {
            cmSvrReg.setProperties(initMgrServiceProp());
        } else {
            cmSvrReg.setProperties(properties);
        }
    }
    public static Dictionary initMgrServiceProp() {
        Dictionary result = new Hashtable();
        // Suppose that the Activator class name is unique across bundles…
result.put(Constants.SERVICE_PID, Activator.class.getName());
        return result;
    }
}

接下来,如 清单 8 所示,将创建一个组件来加载由 OSGi 框架发布的 Configuration Admin Service。


清单 8. ConfigManager 组件 
				
public class DCFrameworkConfigManager {
    private ConfigurationAdmin cm;
    ...
    protected void activate(ComponentContext context) {
        ...
        Configuration config = getFrameworkConfig();
try {
            writeLock.lock();
            if (config.getProperties() == null) {
                config.update(context.getProperties());
            }
        } finally {
            writeLock.unlock();
        }
    }
    public void setConfigAdmin(ConfigurationAdmin cm) {
        this.cm = cm;
    }
    public void unsetConfigAdmin(ConfigurationAdmin cm) {
        this.cm = null;
    }
    public Configuration getFrameworkConfig() throws IOException {
        try {
	readLock.lock();
            return cm.getConfiguration(Activator.class.getName());
        } finally {
            readLock.unlock();
        }
    }
    public void updateFrameworkConfig(Dictionary<String, String> properties)
            throws IOException {
        try {
            writeLock.lock();
            Configuration config = getFrameworkConfig();
            if (config != null) {
                config.update(properties);
            }
        } finally {
            writeLock.unlock();
        }
    }
}

---
<reference bind="setConfigAdmin" cardinality="1..1" 
    interface="org.osgi.service.cm.ConfigurationAdmin" name="ConfigurationAdmin" 
    policy="dynamic" unbind="unsetConfigAdmin"/>
<properties entry="OSGI-INF/initConfig.properties"/>

激活后,ConfigManager 组件会从一个属性文件中启动 bundle 配置并提供一些可用在此 bundle 的任何地方中读取和保存运行时配置和方法。它们受锁定器保护,可处理并发调用情况。

使用 Event Admin Service 处理事件

对于很多系统来说,非常有必要实现一种事件处理模型。OSGi 面向服务的框架可通过 Event Admin Service 提供这样一种实现机制。

为了正确使用 Event Admin Service,需要记住如下三点:

  • 事件发布器需要利用所引用的 EventAdmin 服务发送 Event 对象。
  • 事件订阅器通过实现 handleEvent 方法处理所接受的事件来提供 EventHandler 服务。
  • Event 对象的 event.topics 属性决定了哪个事件处理器可以接收此事件。

OSGi Event Admin Service 以一种更为动态的方式实现了传统的事件处理编程模型,而又能不向这个模型引入新的概念。与本文中介绍的其他 OSGi 服务类似,我们将通过组件对象检索此服务。DS 支持组件既可以是服务提供者又可以是服务消费者,这就使组件可以同时成为事件发布器和事件处理器。

考虑这样的要求:用户可以在应用程序 UI 上观察数据收集进程并能通过 UI 控件随时停止该进程。对于一个数据收集器 bundle 来说,从技术上讲,这意味着在应用程序框架 bundle 和数据收集器 bundle 这两端应具有双通道的事件发送和处理功能(参见如下的 清单 9)。

让我们仅仅以数据收集器 bundle 端为例。同样地,首先检查 Eclipse plugins 文件夹,如果其内没有 org.eclipse.equinox.event_<version>.jar ,就将它复制到此文件夹中,然后将此包导入到这个 bundle manifest。


清单 9. 事件发布器和处理器组件 
				
public class ProfileDataCollectorImpl implements IDataCollector, EventHandler {
    public final static String EVENT_TOPIC =
                    "dw/sample/dc/event/collector/ProfileDataCollectorImpl/status";
    private EventAdmin eventAdmin;
    ...
    public int collectAndOutput() {        		
        while (...) {
            if (isCancelled()) {
                cancelProcess(false);
                return -1;
            }
            ...
            publishEvent(GUIMsg.STATUS_AND_PROGRESS.flag(), 
                "Collecting profile data...", 0, true);
            ...
        }
        ...
    }
    private void publishEvent(int status, String statusMsg, int progress,
        boolean async) {
        Dictionary<String, String> props = new Hashtable<String, String>();
        props.put(FrameworkEventConsts.PARAM_STATUS, String.valueOf(status));
        props.put(FrameworkEventConsts.PARAM_STATUS_MSG, statusMsg);
        props.put(FrameworkEventConsts.PARAM_PROGRESS, String.valueOf(progress));
        if (!async) {
            eventAdmin.sendEvent(new Event(EVENT_TOPIC, props));
        } else {
            eventAdmin.postEvent(new Event(EVENT_TOPIC, props));
        }
    }
    public void handleEvent(Event event) {
        String action = (String) event
                .getProperty(FrameworkEventConsts.PARAM_ACTION);
        if (FrameworkEventConsts.VAL_CANCEL.equalsIgnoreCase(action)) {
            cancelProcess(true);
        }
    }
    ...
}

---
<property name="event.topics" type="String" 
    value="dw/sample/dc/event/framework/UserCmdEventPublisher/uicmd"/>
<service>
   <provide interface="org.osgi.service.event.EventHandler"/>
   <provide interface="dw.sample.dc.api.IDataCollector"/>
</service>
<reference bind="setEventAdmin" cardinality="1..1" 
    interface="org.osgi.service.event.EventAdmin" name="EventAdmin" policy="dynamic" 
    unbind="unsetEventAdmin"/>

在本示例中,请注意 event.topics 属性值的格式。而且,我们还能看到 Event Admin Service 允许开发人员定义可通过 Event 对象传递的数据。

 

使用 Application Admin Service 指定启动模型

到目前为止,我们已介绍了开发 OSGi 应用程序的主要部分,现在,这个示例应用程序应该准备就绪可以运行了。如图 1 所示,一个原生的 OSGi 应用程序是由运行在 OSGi 容器顶端的 bundle 组成的。在默认的情况下,OSGi 控制台会在应用程序启动时出现。如果它是运行在服务器端,那表示没有什么问题。但是如果它作为一个客户端应用程序交付的话,那么就会出现此类问题:如何打 包此应用程序以便它能够像一个现代应用程序一样执行,也就是如何以更为 '专业' 的方式启动而同时又保持其内部的模块化和动态性。

这里,我们引入了一个非常简单的方法,即基于 OSGi Application Admin Service 实现此 Equinox 应用程序模型。

第一步是将 org.eclipse.equinox.app bundle 作为 Require-bundle 添加到此应用程序框架 bundle 的 manifest 中。创建一个类来实现 IApplication 接口,如 清单 10 所示。


清单 10. 实现 IApplication 接口 
				
public class GUIApplication implements IApplication {    
    public Object start(IApplicationContext context) {
        // Invoke the entry GUI object here
        ...
        return IApplication.EXIT_OK;        
    }
    public void stop() {
        // Add the logic when the application quits.
    }
}

其次,通过在 plugin.xml 中声明此扩展将应用程序框架 bundle 定义为一个 Eclipse 应用程序,如清单 11 所示。


清单 11. plugin.xml 
				
<plugin>
    <extension id="GUIApp"
         point="org.eclipse.core.runtime.applications">
      <application cardinality="1">
         <run
               class="dw.sample.dc.launcher.GUIApplication">
         </run>
      </application>
   </extension>      
</plugin>

此应用程序基数指定了此应用程序每次只能有一个实例。由于此 bundle 已经声明了一个扩展,必须在 Bundle-Symbolic manifest 头中追加这个 singleton 指令,如下所示:

Bundle-SymbolicName: dw.sample.dc;singleton:=true 			

接下来,创建一个新的配置以在 Eclipse IDE 中启动此 OSGi 应用程序(参见 图 5)。


图 5. 创建一个新的配置 
屏幕截图显示了将参数添加至一个新配置 

在 Bundles 选项卡,需要单击 Add Required Bundles 来将所有的强制依赖项作为平台 bundle 包括进来。在 Arguments 选项卡,需要添加两个新的参数来启用这个应用程序模型。请注意-application 参数的值应该是 "bundle symbolicname"."extension id" 的格式。

如果我们能够运行这个应用程序并验证所有功能都能按预期的那样在 Eclipse 中正常工作,那么则表明我们已经完成了构建 OSGi 应用程序的开发工作。因此,我们就能够将每个 bundle 项目导出至一个 jar 文件中、对它们进行部署并在一个实际环境中运行所集成的测试,但是这部分内容已超出了本文所讨论的范围。

结束语

本文展示了使用 OSGi 核心服务在 Eclipse 中开发和启动一个模块化应用程序的详细步骤。本文的示例显示了,这个带有 DS 的面向服务组件模型 (Service-Oriented Component Model) 在帮助开发人员有效使用其他 OSGi 核心服务提高模块化应用程序的动态性方面发挥了重要的作用。

分享到:
评论

相关推荐

    osgi 构建模块化云应用之中文版

    在云应用架构方面,本书讨论了如何通过OSGi技术实现应用的模块化和轻量级Web应用的开发。它强调了OSGi技术与SOA(面向服务的架构)的区别与联系,以及如何在云环境中部署模块化应用。书中还探讨了使用JPA、JDBC和...

    Equinox OSGi应用嵌入Jersey框架搭建REST服务

    Equinox OSGi是IBM公司开发的一个开源OSGi实现,它是Eclipse项目的一部分,用于创建模块化、可扩展且轻量级的应用程序。OSGi(Open Service Gateway Initiative)是一种Java平台的标准,它允许开发者将应用程序分解...

    模块化系统的构建专家OSGI.pptx

    * Felix:一个轻量级的OSGi实现 * Equinox:Eclipse基金会提供的一个OSGi实现 * Spring DM:Spring框架提供的一个OSGi实现 * Eclipse Plugin:Eclipse平台提供的一个OSGi实现 五、结论 OSGi是一种java模块化系统的...

    OSGI整合Spring、Mybatis、Spring MVC实现一个登录应用案例

    Mybatis是一个轻量级的持久层框架,它简化了SQL映射和对象关系映射(ORM)的过程。在OSGI环境中,Mybatis可以作为单独的bundle存在,通过OSGI服务注册和查找机制与其他bundle交互。Spring与Mybatis的整合可以让我们...

    基于OSGi和Spring开发Web应用教程

    Spring框架则是一个流行的轻量级Java企业级应用开发框架,它提倡面向接口编程和依赖注入(DI)原则,有助于减少代码耦合度和提高组件的可测试性。Spring-DM(现在称为Spring OSGi)是Spring框架的一个扩展,旨在将...

    基于Equinox开发OSGi应用(一)

    Equinox是Eclipse项目的一个组件,它提供了OSGi规范的实现,使我们能够构建模块化、可扩展且灵活的Java应用程序。OSGi(Open Service Gateway Initiative)是一种Java标准,它允许我们创建由小型、独立组件组成的...

    OSGi与Web容器的整合

    然而,对于轻量级的解决方案,Eclipse Gemini Web项目提供了将Tomcat或Jetty集成到OSGi环境的方法,创建了一个OSGi Web Container。 **2.3 开发环境准备** 为了在Eclipse中开发OSGi Web应用,需要安装相应的插件,...

    osgi 插件开发

    - **嵌入式系统**:由于OSGi的轻量级特性和模块化优势,它在嵌入式系统领域得到了广泛应用。 - **移动应用**:对于资源有限的移动设备而言,OSGi的高效管理机制非常有用。 - **富互联网应用(RIA)**:在RIA开发中,...

    osgi框架开发介绍

    1. **嵌入式系统**:由于其轻量级和动态性,OSGi常用于嵌入式设备,如智能家居、汽车电子系统等,方便软件升级和维护。 2. **企业级应用**:在大型企业应用中,OSGi可以帮助构建松耦合的组件,便于开发、测试和部署...

    SWT应用的开发实例:没有使用到OSGi

    SWT的设计目标是提供一种高效、轻量级且功能丰富的用户界面工具包,与Java Swing相比,SWT通常被认为在性能上更胜一筹。 在这个"SWT应用的开发实例:没有使用到OSGi"中,我们将会探讨如何在不依赖OSGi(OSGi - Open...

    关于OSGI的详细资料

    4. **Jetty**:Jetty是一个开源的轻量级Web服务器和Java Servlet容器。在本教程中,我们将使用Jetty 5.1.14作为HTTP服务器。 #### 必要的Bundles介绍 为了搭建一个基本的OSGi环境并创建一个简单的HelloWorld示例,...

    OSGI实战.zip

    - **嵌入式系统**:OSGI的轻量级和模块化特性使其在物联网设备和嵌入式系统中广泛应用。 - **企业级应用**:在复杂的分布式系统中,OSGI的动态性和模块化有助于构建可扩展的应用服务器。 - **插件系统**:如...

    OSGI学习手册及实践

    - **Oscar**:一个轻量级的OSGI实现,适合于资源受限的环境。 - **Knopflerfish**:一款成熟的OSGI框架,特别适用于服务器端应用。 #### 4. OSGI的关键组成部分 - **ClassLoader**:OSGI使用独立的类加载器为每个...

    OSGI实战.docx

    OSGI(Open Services Gateway Initiative)是一种Java模块化系统,它为构建可升级、可扩展且模块化的应用程序提供了基础。在“OSGI实战”文档中,作者深入浅出地介绍了如何在实际开发环境中应用OSGI技术。 一. 序 ...

    Spring与OSGI整合 计算器例子(转) +附整合代码和spring-osgi核心jar

    Spring框架则是一个流行的轻量级Java应用框架,用于简化开发和管理依赖关系。整合Spring和OSGi可以利用OSGi的模块化特性,使得Spring应用更加灵活和可扩展。 首先,我们需要了解Spring在OSGi环境中的工作方式。...

    eclipse插件开发实战

    Eclipse 的核心是插件加载器,整个平台由众多插件组成,其架构特点在于轻量级的核心与高度可扩展的设计。在启动时,插件加载器会读取 `plugin.xml` 文件中的信息,从而构建起整个插件体系。 - **OSGi (Open ...

    Eclipse中搭建Felix运行环境

    Felix是OSGI规范的一种实现,它是Apache基金会的一个开源项目,提供了一个轻量级、高效的OSGI运行时环境。本篇文章将详细介绍如何在Eclipse中搭建Felix运行环境,以便进行OSGI企业应用的开发。 首先,我们需要安装...

    你好---OSGI

    开放源码的OSGi容器如Equinox和Knoflerfish,为企业开发者提供了轻量级且易于集成的解决方案。Equinox不仅是Eclipse IDE的基础,也是遵循OSGi规范4版实现的一个强大容器,它实现了规范中的所有强制和大部分可选功能...

    OSGI学习整理

    这个框架最初是为了在各种设备如机顶盒、服务网关、手机和汽车上提供服务基础平台而设计的,但随着时间的发展,它的应用范围已经远远超出了最初的设想,成为了一个广泛应用在PC和服务器端的轻量级、松耦合的、面向...

    OSGI入门和整合Spring

    **Spring Framework** 是一个轻量级的 Java 应用程序框架,主要用于简化企业级应用程序的开发。Spring 支持 IoC (Inversion of Control) 控制反转和 AOP (Aspect Oriented Programming) 面向切面编程等技术。 - **...

Global site tag (gtag.js) - Google Analytics