- 浏览: 1650301 次
- 性别:
文章分类
- 全部博客 (2929)
- 非技术 (18)
- Eclipse (11)
- JAVA (31)
- 正则表达式 (0)
- J2EE (4)
- DOS命令 (2)
- WEB前端 (52)
- JavaScript (69)
- 数据库 (8)
- 设计模式 (0)
- JFreechart (1)
- 操作系统 (1)
- 互联网 (10)
- EasyMock (1)
- jQuery (5)
- Struts2 (12)
- Spring (24)
- 浏览器 (16)
- OGNL (1)
- WebService (12)
- OSGi (14)
- 软件 (10)
- Tomcat (2)
- Ext (3)
- SiteMesh (2)
- 开源软件 (2)
- Hibernate (2)
- Quartz (6)
- iBatis (2)
最新评论
本文是《你 好,OSGi 》系列的第四部分。下面讲述OSGi服务。对OSGi不是很了解的读者可以先阅读OSGi是什么 一文。
OSGi服务
前面我们提到,OSGi架构非常适合我们实现面向服务的应用(SOA)。它可以让Bundles导出服务,而其它的Bundles可以在不必了解源 Bundles任何信息的情况下消费这些导出的服务。由于OSGi具有隐藏真实的服务实现类的能力,所以它为面向服务的应用提供了良好的类与接口的组合。
在OSGi框架中,源Bundle在OSGi容器中注册POJO对象,该对象不必实现任何接口,也不用继承任何超类,但它可以注册在一个或多个接口 下,并对外提供服务。目标Bundle可以向OSGi容器请求注册在某一接口下的服务,一旦它发现该服务,目标Bundle就会将该服务绑定到这个接口, 并能调用该接口中的方法。下面我们举个例子,以便我们能更好理解与OSGi相关的这些概念。
5.1. 导出服务
在本小节中,我们将更新HelloService Bundle,以便它能把HelloServiceImpl类的对象导出为服务,具体步骤如下:
1) 修改com.javaworld.sample.HelloService Bundle中的MANIFEST.MF文件,让它导入org.osgi.framework包(译者注,这一步我们已经完成);
2) 新建Java类com.javaworld.sample.impl.HelloServiceActivator.java,其源代码如清单7所示;
源代码清单7. HelloServiceActivator.java
public class HelloServiceActivator implements BundleActivator {
ServiceRegistrationhelloServiceRegistration;
public void start(BundleContext context)throws Exception {
HelloService helloService = newHelloServiceImpl();
helloServiceRegistration=context.registerService(HelloService.class.getName(), helloService, null);
}
public void stop(BundleContext context)throws Exception {
helloServiceRegistration.unregister();
}
}
请注意,在源Bundle中,我们应使用BundleContext.registerService()方法导出服务,这个方法带三个参数:
a) 该方法第一个参数为您要注册的服务的接口名称。如果您想把您的服务注册到多个接口下,您需要新建一个String数组存放这些接口名,然后把这个数组作为 第一个参数传给registerService()方法。在示例代码中,我们想把我们的服务导出到HelloServer接口名下;
b) 第二个参数是您要注册的服务的实际Java对象。在示例代码中,我们导出HelloServiceImpl类的对象,并将其作为服务;
c) 第三个参数为服务的属性,它是一个Dictionary对象。如果多个Bundle导出服务的接口名相同,目标Bundle就可以使用这些属性对源 Bundle进行过滤,找到它感兴趣的服务。
3) 最后,请修改HelloServiceBundle中的MANIFEST.MF文件,将Bundle-Activator属性头的值改为 com.javaworld.sample.service.impl.HelloServiceActivator。
现在HelloService Bundle就可以导出HelloServiceImpl对象了。当OSGi容器启动HelloServiceBundle时,它会将控制权交给 HelloServiceActivator.java类,HelloServiceActivator将HelloServiceImpl对象注册为服 务。下面,我们开始创建该服务的消费者。
5.2. 导入服务
在本小节中,我们将修改上面开发的HelloWorld Bundle,以便让它成为HelloService服务的消费者。您主要需要修改HelloWorldBundle中的Activator.java代 码,修改后的代码如源代码清单8所示:
源代码清单8. HelloWorld Bundle中的Activator.java
packagecom.javaworld.sample.helloworld;
importorg.osgi.framework.BundleActivator;
importorg.osgi.framework.BundleContext;
importorg.osgi.framework.ServiceReference;
importcom.javaworld.sample.service.HelloService;
publicclass Activator implements BundleActivator {
ServiceReference helloServiceReference;
public void start(BundleContext context)throws Exception {
System.out.println("HelloWorld!!");
helloServiceReference=context.getServiceReference(HelloService.class.getName());
HelloService helloService=(HelloService)context.getService(helloServiceReference);
System.out.println(helloService.sayHello());
}
public void stop(BundleContext context)throws Exception {
System.out.println("Goodbye World!!");
context.ungetService(helloServiceReference);
}
}
在上面的代码中,BundleContext.getServiceReference()方法将为注册在HelloService接口下的服务返 回一个ServiceReference对象。如果存在多个HelloService服务,该方法会返回排行最高的服务(服务的排行是通过 Constants.SERVICE_RANKING属性指定的)。您一旦获得ServiceReference对象,您就可以调用其 BundleContext.getService()方法获取真实的服务对象。
您可以参照运行Bundle的方法运行上面的示例应用,请点击“RunàRun…”菜单,并确保HelloWorld和HelloService这 两个Bundle被选中。当您启动HelloServiceBundle时,您会在控制台上看到 “InsideHelloServiceImple.sayHello()”,这个消息是由HelloServiceImpl.sayHello()方法 打印出来的。
5.3. 创建服务工厂
在上节中,我们学会了如何使用OSGi框架新建一个Java对象,并把它注册为一个服务,然后让其它的Bundle去消费这个服务。如果您看一下 HelloServiceActivator.start()方法,您会注意到我们在start()方法中新建了HelloServiceImpl类对 象,然后将它注册到HelloService接口名下。这样注册后,任何其它的Bundle在请求HelloService服务时,OSGi容器将返回同 一对象。
在大多数情况下,这样的实现方法没有问题。但是,比如说我们要为每一个Bundle消费者返回不同的HelloServiceImpl对象,再比如 说,您的服务对象要提供的服务为打开一个数据库连接,但并不是马上就打开它,而是在真正需要的时候才打开这个数据库连接。
对这两种情况,我们的解决方法是,新建一个类实现ServiceFactory接口,并把该类的对象注册为服务,但并不是注册实际的服务对象。一旦 您完成这一步,其它Bundle在请求该服务时,您的ServiceFactory实现类将接管该请求,ServiceFactory会为每个 Bundle新建一个服务对象,并将真实服务的创建时间延迟到有人真正需要该服务的时候。
下面我们将使用ServiceFactory更新我们上面开发的 com.javaworld.sample.HelloServiceBundle,具体步骤如下:
1) 新建工厂 类HelloServiceFactory.java,源代码如清单9所示。
源代码清单9 . HelloServiceFactory.java
public class HelloServiceFactory implements ServiceFactory{
private int usageCounter = 0;
public Object getService(Bundle bundle,ServiceRegistration registration) {
System.out.println("Create objectof HelloService for " + bundle.getSymbolicName());
usageCounter++;
System.out.println("Number ofbundles using service " + usageCounter);
HelloService helloService = newHelloServiceImpl();
return helloService;
}
public void ungetService(Bundle bundle,ServiceRegistration registration, Object service) {
System.out.println("Release objectof HelloService for " + bundle.getSymbolicName());
usageCounter--;
System.out.println("Number ofbundles using service " + usageCounter);
}
}
从上面的代码中,我们可以看到,ServiceFactory接口定义了两个方法:
a) getService()方法:当某个Bundle第一次使用BundleContext.getService(ServiceReference)方 法请求一个服务对象时,OSGi框架会调用该方法。在源代码清单9中,我们用这个方法为每个Bundle新建并返回不同的 HelloServiceImpl对象,如果这个对象不是null,OSGi框架会缓存这个对象。如果同一个Bundle再次调用 BundleContext.getService(ServiceReference)方法,OSGi将返回同一个服务对象。
b) ungetService()方法:当Bundle释放服务时,OSGi容器可以调用该方法销毁服务对象。在源代码清单9中,我们使用 usageCounter变量来跟踪服务的使用数目,并打印出该服务的客户端数量。
2) 修改HelloService Bundle中的HelloServiceActivator.java的start()方法,让它注册到ServiceFactory接口名下,而不是 注册到HelloService接口。详细代码如清单10所示:
源代码清单10. 修改后的HelloServiceBundle中的HelloServiceActivator.java
package com.javaworld.sample.service.impl;
importorg.osgi.framework.BundleActivator;
importorg.osgi.framework.BundleContext;
importorg.osgi.framework.ServiceRegistration;
importcom.javaworld.sample.helloservice.HelloServiceFactory;
importcom.javaworld.sample.service.HelloService;
publicclass HelloServiceActivator implements BundleActivator {
ServiceRegistrationhelloServiceRegistration;
public void start(BundleContext context)throws Exception {
HelloServiceFactory helloServiceFactory= new HelloServiceFactory();
helloServiceRegistration=context.registerService(HelloService.class.getName(), helloServiceFactory,null);
}
public void stop(BundleContext context)throws Exception {
helloServiceRegistration.unregister();
}
}
现在,您可以试运行示例代码。您会注意到,当HelloWorld Bundle启动时,服务计数器变为1;当HelloWorldBundle停止时,服务计数器的数目将变为0。
5.4. 跟踪服务
在“OSGi服务”小节,您学会了如何使用服务的接口名搜索服务。但如果有多个Bundle使用同一接口名注册服务,那会发生什么呢?这 时,OSGi容器将返回排行最高的服务,即,返回注册时那个SERVICE_RANKING属性值最大的服务。如果有多个服务的排行值相等,那么OSGi 容器将返回PID值最小的那个服务。
但是,如果您的服务消费者需要了解某一接口下的服务对象何时注册、何时取消注册,这时,您应使用ServiceTracker类。下面,我们看看如 何使用服务跟踪器来修改我们的示例代码,具体步骤如下。
1) 修改HelloWorldBundle的MANIFEST.MF文件,让它导入org.osgi.util.tracker包;
2) 新建类HelloServiceTracker.java,其源代码参见清单11。
源代码清单11.HelloServiceTracker.java
public class HelloServiceTracker extends ServiceTracker {
public HelloServiceTracker(BundleContext context) {
super(context, HelloService.class.getName(),null);
}
public Object addingService(ServiceReference reference) {
System.out.println("Inside HelloServiceTracker.addingService " + reference.getBundle());
return super.addingService(reference);
}
public void removedService(ServiceReference reference, Object service) {
System.out.println("Inside HelloServiceTracker.removedService " + reference.getBundle());
super.removedService(reference, service);
}
}
在上面的HelloSerivceTracker类的构造函数中,您可以看到,我们把HelloService接口名传入其父类中,这相当于 说,HelloServiceTracker应跟踪注册到HelloService接口名下的所有服务,HelloServiceTracker继承自 ServiceTracker类,实现了下面两个方法:
a) addingService()方法:当Bundle使用接口名注册服务时,该方法将会被调用;
b)removedService()方法:当Bundle取消注册某个接口名下的服务时,该方法将会被调用。
3) 用HelloServiceTracker类更新我们的Activator.java类,以便让它来管理服务,而不是直接去查找它们,源代码请参见清单 12。
源代码清单12. 使用了HelloServiceTracker的Activator.java
public class Activator implements BundleActivator {
HelloServiceTracker helloServiceTracker;
public void start(BundleContext context) throws Exception {
System.out.println("Hello World!!");
helloServiceTracker= new HelloServiceTracker(context);
helloServiceTracker.open();
HelloService helloService = (HelloService)helloServiceTracker.getService();
System.out.println(helloService.sayHello());
}
public void stop(BundleContext context) throws Exception {
System.out.println("Goodbye World!!");
helloServiceTracker.close();
}
}
我们看到,在初始的start()方法中,我们首先新建一个HelloServiceTracker对象,然后要求这个对象跟踪 HelloService接口下的服务。这时,我们可以调用getService()方法获得HelloService对象。
如果您试运行上面的示例代码,您会注意到,在启动或停止HelloSerivceBundle时,OSGi容器都会调用 HelloServiceTracker对象的addingService()方法或removedService()方法。
发表评论
-
OSGi是什么:Java语言的动态模块系统
2010-05-31 14:19 642之前51CTO曾发过一篇文章叫做《OSGi为什么重要:向模块化 ... -
OSGi Bundle之Hello World
2010-05-31 14:20 691本文是《你 好,OSGi 》系列的第二部分。之前曾介绍过O ... -
OSGi依赖性管理:Bundle访问域
2010-05-31 16:12 684本文是《你 好,OSGi 》系列的第三部分。之前介绍过OS ... -
OSGi和Spring入门:什么是Spring动态模型(Spring DM)?
2010-05-31 17:46 1029【51CTO精选译文】本文 ... -
OSGi与Spring:设置Spring DM开发环境
2010-06-01 09:46 627【51CTO精选译文】本文 ... -
使用Spring DM创建Hello World,以及OSGi服务
2010-06-01 13:24 765【51CTO精选译文】本文是《你好,OSGi 》系列的第 ... -
使用OSGi构建面向服务的联络管理应用程序
2010-06-01 14:44 720【51CTO精选译文】本文是《你好,OSGi 》系列的第 ... -
OSGi与Spring DM:使用Spring DataSource
2010-06-07 12:53 647【51CTO精选译文】本文是《你好,OSGi 》系列的第 ... -
初探OSGi Web应用开发利器Equinox:环境设置
2010-06-07 12:55 809【51CTO精选译文】在之前的《你好,OSGi》系列 中, ... -
打造一个Hello World OSGi Web应用程序
2010-06-07 12:59 564【51CTO精选译文】在《你好,OSGi 》的之前一篇文章 ... -
部署并运行你的OSGi Web应用程序
2010-06-07 13:02 436【51CTO精选译文】本文 ... -
打造一个基于OSGi的Web Application
2010-06-12 09:51 1188动机和目标 OSGi技术 ... -
OSGi中获取Service的几种方式
2010-06-12 10:01 751在OSGi中,Service是动态管理的,OSGi容器提供 ...
相关推荐
本教程主要针对面向服务架构(Service-Oriented Architecture, SOA)的开发者,旨在帮助他们更好地理解和应用OSGI技术。 **OSGI核心概念** 1. **模块系统**:OSGI的核心是它的模块系统,称为“Bundle”。每个...
**SOA** 是一种架构风格,强调构建可重用、松耦合的业务服务,以满足不断变化的业务需求。它允许跨语言的分布式通信,强调按需组装服务以形成解决方案。SCA是实现SOA的一种编程模型,提供异步服务调用的能力,支持...
例如,SOA定义了服务接口和交互规则,OSGi负责模块化和管理服务的生命周期,而ESB作为连接器,使得这些服务能够高效、安全地通信。这样的架构可以有效降低系统的复杂度,提升系统的灵活性和可维护性。 博文链接可能...
5. 设计良好的治理架构:监控服务质量和性能,确保服务的稳定性和安全性。 总之,SOA和BC的结合为企业架构提供了强大的灵活性和可扩展性,而SCA则为实现这一目标提供了标准化的工具和框架。通过深入理解这些概念并...
3. **SOA兼容性**:OSGi遵循面向服务的架构(SOA)原则,创建规范且可重用的模块服务,使得不同服务之间可以高效协作。 在实际应用中,OSGi被广泛应用于各个领域,例如: 1. **宝马汽车的应用控制系统**:利用OSGi...
### 面向服务体系架构(SOA)与业务组件(BC)的核心概念解析 #### 一、概述 随着信息技术的不断发展,企业的信息化建设越来越依赖于高效、灵活且可扩展的技术架构。面向服务体系架构(Service-Oriented ...
Osgi基于服务导向架构(SOA),它的核心是bundle,每个bundle都是一个自包含的单元,拥有自己的类路径、生命周期管理和依赖管理。Osgi提供了一种动态的方式来管理这些bundle,允许它们在运行时安装、启动、停止、...
- **Swordfish:基于OSGi的SOA架构**:Swordfish是Eclipse项目中的一个重要组成部分,它基于OSGi框架实现了SOA架构。这种方式使得服务可以在运行时动态加载和卸载,极大地提高了系统的灵活性。 - **Eclipse与Web...
例如,在SOA(Service-Oriented Architecture)环境中,OSGI服务可以作为微服务的基础,实现服务的独立部署和升级。 3. **嵌入式系统**:由于其小体积和低内存占用,OSGI也常被用于嵌入式设备,如路由器、智能家居...
2. **服务框架**:OSGi定义了一个服务框架,允许组件之间以服务的形式进行交互,从而实现了动态的依赖管理和插件式的架构。 3. **生命周期管理**:通过提供一个生命周期管理模型,OSGi使得组件可以在运行时动态安装...
#### Eclipse Swordfish:基于OSGi的SOA架构 Eclipse Swordfish是一个由Eclipse基金会支持的项目,旨在利用OSGi技术构建面向服务的架构(SOA)。Swordfish不仅关注于OSGi本身,而且还整合了其他关键的SOA技术,如...
标题“OSGi and Equinox”和描述“OSGi and ...了解这些概念对于当今面向服务的架构(SOA)和微服务架构趋势具有非常重要的意义。模块化不仅仅是技术层面的优化,它在业务敏捷性和软件维护性方面也扮演着核心角色。
Java应用架构设计:模块化模式与OSGi 英文版 中文版介绍: 全球资深Java技术专家的力作,系统、全面地讲解如何将模块化设计思想引入开发中,涵盖18个有助于实现模块化软件架构的模式 中文目录: 第一部分 模块化...
3. **服务导向架构**:书中详细解释了OSGi如何支持服务导向架构(SOA)。OSGi服务允许组件动态发布和发现服务,使得应用能根据需求自我调整,增强了系统的灵活性和适应性。 4. **动态性**:OSGi的一个显著特性是其...
文章中描述的DscG()M(Dynamic Service Composition Mechanism基于OSGi)机制包含了两个关键部分:服务组合路径选择机制和服务重定向机制。路径选择机制负责生成满足动态网络需求的服务组合路径,即在多个服务之间...
Java应用架构设计:模块化模式与OSGi 英文版 中文版介绍: 全球资深Java技术专家的力作,系统、全面地讲解如何将模块化设计思想引入开发中,涵盖18个有助于实现模块化软件架构的模式 中文目录: 第一部分 模块化的...
4. **服务导向架构(SOA)**:OSGi支持服务注册和发现,使得组件之间可以通过服务接口进行交互,而不是直接引用对方。书中可能会讲解如何设计和实现OSGi服务。 5. **开发工具与框架**:介绍Eclipse Equinox、Apache...