- 浏览: 270554 次
- 性别:
- 来自: 新乡
文章分类
- 全部博客 (227)
- servciemix (10)
- db (18)
- javaTools (4)
- hibernate (31)
- web (3)
- spring (14)
- design pattern (4)
- java security (3)
- portal (1)
- ejb (6)
- session (2)
- java_lang (21)
- jbpm (29)
- struts (7)
- orgRights (2)
- project manager Jira (7)
- 跨库事务 (2)
- mysql (14)
- ubuntu (7)
- osgi (9)
- maven ant make (4)
- 分布式 高并发 高性能 (5)
- virgo-dm_server (0)
- osgi web (3)
- platform (1)
- smooks (1)
- business (1)
- 职场生涯 (14)
- Java编码格式 (2)
- web服务 (1)
- 计算机使用 (1)
- 健康工作生活的保障,工作中务必抛掉的不良心态 (4)
- 电信-网络监控 (1)
- 多线程-multithread (1)
- 海量数据-高性能 (2)
- Mybatis (1)
- web开发平台研发 (0)
- oracle (0)
- 应用服务器调优 (0)
- web前端 (0)
- servlet-jsp (0)
- tomcat (2)
- newtouch (1)
- portal_liferay (2)
- version control (1)
- apm-impact (2)
- tools (1)
- 研发管理 (1)
- 电商业务 (1)
- 生鲜电商市场调查 (0)
- PBX (0)
- 房东 (0)
最新评论
-
lifuchao:
...
权限问题 -
Branding:
谢谢,受教了,另外,CONN AS SYSDBA,必须是在操作 ...
Oracle密码忘记了怎么办? -
zhuchao_ko:
...
Portal实现原理 -
败类斯文:
不知道改哪里。。。木有见到红色。。表示悟性低了、、
jira error: Neither the JAVA_HOME nor the JRE_HOME environment variable is defin -
c__06:
正文:假如事务我是这样定义的: <tx:method n ...
Spring中Transactional配置
OSGi Bundle的构建策略及实践 .
分类: OSGi Architecture Design 2008-02-18 01:02 1286人阅读 评论(0) 收藏 举报
软件编程发展到今天可以看作是一个量变引发质变的过程。最初,程序开发面向过程,开发人员需要编写大量的过程代码,随着过程代码的不断积累(量变产 生),从代码维护和重用的角度,过程开发变得越来越不适应,质变产生,面向对象的开发逐渐被采用。由于面向对象的开发很好的封装了过程,而且从面向对象的 角度可以很好的描述实际应用中的需求模型,因此面向对象的开发逐渐成为主流。同样,随着面向对象开发的不断应用(量变产生),出现了大量的可复用的类及 包,维护这些类/包变得越来越困难,而且,尽管面向对象的编程机制可以很好的适应小规模应用的开发,但随着应用系统的规模越来越大,如同用细小的沙粒构建 堤坝,面向对象的机制难于适应,质变产生,面向组件的开发被引入开发过程。面向组件的开发目前仍可以认为是处于一种探索状态,目前还不存在一种统一的标准 可以遵循。
从另一个角度,历史是今天存在的基础,没有历史就没有今天。同样的道理,应用系统采用面向组件的开发实现,组件仍需要对象来构造,而对象在一定程度上是封 装的功能过程,三者相辅相成。不管是从上而下还是从下而上,应用系统需求模型在其实现过程中,系统设计者应该充分关注组件、对象和功能过程三个层面。
OSGi可以看作是面向组件开发的一种思路和基础环境。在OSGi环境中实现应用系统的需求模型要求开发人员对组件、对象开发具有充分的理解。衡量一个应 用系统实现好坏的标准之一是该系统是否是松耦合高内聚。面向对象的开发实现此目标的关键是接口/抽象的应用,OSGi面向组件的开发在此基础之上充分利用 了对象类包封装的机制。
1. Bundle的构建策略
通常,当我们构建应用系统时,我们需要充分重视所构建应用的业务需求模型即领域模型,同样的,在用软件代码实现业务需求模型时,我们也应当对软件系统的架 构模型给予充分的重视。采用OSGi技术实现应用系统时,展现在我们面前的将是一个个的Bundle组件,此时,我们必须首先弄清楚我们要构建什么样的 Bundle。
1.1 明确Bundle的构建需求及实现粒度
从需求模型的角度看,Bundle可以看作是需求模型中的一个功能模块实现,因此,在开发Bundle之前系统开发人员必须明确Bundle的功能需求。 需求模型中的功能模块的边界可大可小,同样,Bundle的实现粒度也是可大可小,极端情况下,小的Bundle可以仅实现一个微小的功能,大的 Bundle可以实现整个业务系统。
以记录日志为例,如果记录日志仅输出到控制台,则一个类就可以实现整个的功能,如果记录日志输出到数据库系统,则开发人员需要在整个功能用一个 Bundle实现,还是将日志记录功能和记录信息的数据库存储分为两个不同的Bundle实现,两个选择甚至更多的选择中做出决策。通常这个问题在现有的 软件开发方式中不需要过多的重视,但在OSGi开发中,开发人员必须根据需求确定Bundle的实现粒度。
1.2 确定Bundle的类型
我们在面向对象的系统开发过程中,经常会将一些通用的功能设计成为工具类,多个工具类封装为一个工具类包。由于OSGi开发建立在面向对象的开发之上, Bundle的开发也存在这种特点。OSGi开发的另一个特点是服务机制的引入,一个Bundle可以将其提供的功能发布成为一个或多个服务,供其他 Bundle查找使用。此外,建立在OSGi环境之上的组件开发也区别于通常的组件开发方式,因为我们可以利用OSGi环境提供的某些特性(参见下一节 充分利用OSGi环境的特性)。综上所述,我们可以将Bundle划分为如下几种类型(实际开发中,并不存在清晰的边界):
•Utility Bundle
这种Bundle与通常开发方式中的工具类或工具类包没有本质的区别,仅仅是将这些工具类发布到OSGi环境中,这些工具类也不依赖任何的OSGi环境或 特性。通常,这种Bundle特别适合目前存在的众多的第三方组件引入到OSGi环境中直接供OSGi开发人员使用。例如,我们可以将Apache开源项 目Log4j发布的工具包通过修改其META-INF目录下的MANIFEST.MF文件,添加Bundle的元数据信息就可以直接将其封装为可供 OSGi环境中其他Bundle使用的工具类Bundle。
•依赖OSGi特性的Bundle
这类Bundle可以被其他Bundle引用,为其提供功能,但是这类Bundle不能离开OSGi运行环境,否则不能使用。举例来说,一个提供数据缓存 功能的Bundle可能使用Bundle的数据存储区来缓存数据。Bundle的数据存储区的位置对Bundle开发者来说是透明的(参见下一节 充分利用OSGi环境的特性)。如果将该Bundle的数据缓存功能迁移到OSGi运行环境之外,则必须修改实现添加对缓存区位置的处理功能。
•引用和(或)发布OSGi服务的Bundle
这类Bundle也可以认为是依赖OSGi特性的Bundle,唯一的区别就是,该类Bundle充分利用的OSGi中服务的特性,引用其他Bundle 发布的服务和(或)向OSGi环境中发布自己的服务。OSGi环境提供的服务机制可以使得系统的实现遵循最大程度的松耦合。
1.3 隐藏Bundle的功能接口
组件开发除了应对系统的开发规模之外,其最重要的目标是降低系统耦合。开发人员采用OSGi Bundle开发时,应尽量屏蔽Bundle所提供功能的内部实现机制,仅将为其他Bundle提供的交互接口暴露出来。在OSGi中,这可以通过两种方 式,一种是通过Export供其他Bundle引用的类包;一种是向OSGi环境发布服务。
在Equinox中,Bundle内部实现的类包通常以"internal"标注,如org.eclipse.equinox.internal.cm.reliablefile。标注为"internal"的类包通常不包含在Export列表中,或者通过"x-internal"属性标记(该属性仅在Eclipse开发环境中提供)。
隐藏Bundle功能接口的一种良好机制是通过OSGi服务。开发人员仅将自己开发的Bundle的接口类包发布给其他Bundle可见,同时,将功能接 口的实现注册为OSGi中的服务,其他Bundle通过查找OSGi服务注册表获取该服务,通过服务的接口调用服务的功能。
1.4 尽可能应用OSGi提供的标准服务
OSGi联盟为一些经常用到的功能定义了标准服务,如应用程序管理服务,日志服务,事件服务,配置管理服务,用户管理服务,HTTP服务等等。如果开发人 员采用的OSGi环境提供了上述服务的实现,且这些服务实现满足系统的需求,则开发人员应尽可能使用这些服务,而不是为这些类似的功能定义自己的实现。
2.充分利用OSGi环境的特性
2.1 OSGi环境的动态特性
OSGi是一个动态的环境,OSGi运行环境内部状态的变化通过事件发布/监听机制进行交互。开发人员在构建Bundle时应充分利用OSGi环境的事件 监听机制。如,开发人员可以在自己的Bundle中注册Bundle事件的监听用来处理其他Bundle的安装,启动,停止,卸载等事件。
OSGi运行环境内部的事件主要包括三类:
•框架事件(FrameworkEvent)
STARTED 框架已经启动
ERROR 某个Bundle启动过程中引发错误
WARNING 某一Bundle引发一个警告
INFO 某一Bundle引发一个INFO类型的事件
PACKAGES_REFRESHED PackageAdmin.refreshPackage操作执行完成
STARTLEVEL_CHANGED StartLevel.setStartLevel操作执行完成
•Bundle事件(BundleEvent)
INSTALLED Bundle被安装到OSGi环境后系统发布该事件
RESOLVED Bundle被成功解析
LAZY_ACTIVATION Bundle将被延迟激活
STARTING Bundle正在被激活
STARTED Bundle被成功激活
STOPPING Bundle被停止
STOPPED Bundle正在被停止
UPDATED Bundle被更新
UNRESOLVED Bundle被UNRESOLVED
UNINSTALLED Bundle被卸载
•服务事件(ServiceEvent)
REGISTERED 服务被注册
MODIFIED 服务被修改
UNREGISTERING 服务正在被注销
关于上述事件的详细信息参考OSGi API文档。
下述代码展示了如何在Bundle组件中通过实现FrameworkListener,BundleListener和ServiceListener接口,并使用BundleContext注册监听OSGi环境的各种事件:
package com.example;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleListener;
import org.osgi.framework.FrameworkEvent;
import org.osgi.framework.FrameworkListener;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
public class Activator implements BundleActivator, FrameworkListener,
BundleListener, ServiceListener {
public void start(BundleContext context) throws Exception {
//注册监听
context.addFrameworkListener(this);
context.addBundleListener(this);
context.addServiceListener(this);
}
public void stop(BundleContext context) throws Exception {
}
//处理框架事件
public void frameworkEvent(FrameworkEvent event) {
if ((event.getType() & FrameworkEvent.ERROR) != 0) {
System.err.println("Framework ERROR: " + event.getBundle());
}
}
//处理Bundle事件
public void bundleChanged(BundleEvent event) {
if ((event.getType() & BundleEvent.STARTED) != 0) {
System.err.println("Bundle STARTED: " + event.getBundle());
} else if ((event.getType() & BundleEvent.STOPPED) != 0) {
System.err.println("Bundle STOPPED: " + event.getBundle());
}
}
//处理服务事件
public void serviceChanged(ServiceEvent event) {
if ((event.getType() & ServiceEvent.REGISTERED) != 0) {
System.err.println("Service REGISTERED: "
+ event.getServiceReference());
}
}
}
2.2 Bundle的生命周期及OSGi上下文特性
在Java虚拟机运行环境中,类的生命周期开始于虚拟机的加载,终止于被提前卸载或虚拟机停止,通常不需要开发人员干预。在OSGi环境中,开发人员可以参与Bundle的生命周期过程并能够获取Bundle在OSGi环境中运行的上下文。
通过实现org.osgi.framework.BundleActivator接口,并在Bundle的元数据头属性"Bundle- Activator"中指明该接口的实现类,如"Bundle-Activator: com.example.Activator"。当Bundle被启动或停止时,OSGi框架会将该Bundle的运行上下文BundleContext 注入到该实现类实例中,开发人员可以在该Bundle的运行过程中使用该上下文访问OSGi环境信息,访问OSGi环境中的其他Bundle,注册事件监 听,发布或引用服务等。
下面的代码片段展示了如何利用Bundle运行上下文与OSGi环境进行交互:
public void start(BundleContext context) throws Exception {
// 获取OSGi环境中的所有安装的bundle
for (Bundle bundle : context.getBundles()) {
System.out.println("Bundle Symbolic Name: "
+ bundle.getSymbolicName());
}
// 获取OSGi运行环境中的属性(查找范围包括系统属性)
System.out.println("osgi.framework = "
+ context.getProperty("osgi.framework"));
//注册其他Bundle
context.installBundle("file:C://test_bundle_1.0.0.jar");
//在该Bundle的数据存储区中构建datacache.file文件
context.getDataFile("datacache.file");
//注册监听
context.addFrameworkListener(this);
context.addBundleListener(this);
context.addServiceListener(this);
}
2.3 Bundle的资源管理特性
在通常的应用系统开发中,开发人员通常要考虑配置文件的存储路径,系统临时文件的存储路径等信息。由于OSGi环境中Bundle实际上是由一组文件资源 构成,开发人员在开发Bundle时可以充分利用这种特点,使用Bundle存储与Bundle相关的配置信息。OSGi环境在运行时为每一个 Bundle构建一个序列化数据存储区,开发人员可以使用该存储区存储Bundle在运行时生成的临时信息。
下述代码片段展示了如何通过Bundle提供的功能接口获取Bundle内部的资源:
•context.getBundle.getEntry("") 只查询Bundle内部资源,返回Bundle的URL,该URL与实现相关,如:bundleentry://256/
•context.getBundle.getEntry("/") 只查询Bundle内部资源,返回Bundle的URL,该URL与实现相关
•context.getBundle.getEntry("/build.properties") 只查询Bundle内部资源,返回Bundle内部build.properties文件的URL,该URL与实现相关,如:bundleentry://256/build.properties
•context.getBundle().getResource("build.properties") 使用Bundle的ClassLoader查询Bundle类域内的资源,如果Bundle不能被解析(RESOLVED),则只查询Bundle内部资源,返回Bundle内部build.properties文件的URL,该URL与实现相关。
开发人员在获取上述资源的URL后,可以转换成与Bundle运行系统相关的文件URL,如:file:C:/test_bundle_1.0.0。
下述代码片段展示了通过BundleContext接口获取Bundle运行时数据存储区资源:
•context.getDataFile("") 返回该Bundle的运行时数据存储区位置,如:E:/worksapce/.metadata/.plugins/org.eclipse.pde.core/CobWeb/org.eclipse.osgi/bundles/256/data
•context.getDataFile("config.xml") 返回该Bundle的运行时数据存储区内的config.xml文件,如果该文件不存在,则创建该文件。
2.4 面向服务的组件特性
OSGi的服务层提供了一个动态服务发布,绑定和查找模型,所谓的服务即指实现了某个(些)接口的Java对象。在面向对象的系统开发中,接口在分离系统的耦合方面扮演至关重要的角色,OSGi环境充分利用了这一点。
OSGi运行框架维护着一个服务注册表,Bundle可以通过Bundle上下文向该服务注册表中发布服务(只需指明服务实现的接口,服务的实例和服务的 属性),也可以使用Bundle上下文从服务注册表中根据接口名称及服务的属性查找其他Bundle注册的服务。在此模式下,Bundle之间的耦合关系 只存在接口层面,而与接口的实现无关。
下述代码片段展示了如何向OSGi服务注册表发布服务以及如何查找其他Bundle发布的服务:
public void start(BundleContext context) throws Exception {
//获取OSGi Log服务的服务引用
ServiceReference logSr = context.getServiceReference(LogService.class.getName());
//根据Log服务引用获取LogService服务实例
log = (LogService) context.getService(logSr);
//创建StringService接口服务实例
StringService ss = new StringServiceImpl(log);
//设定StringService的属性
Hashtable
//使用BundleContext注册发布StringService服务
context.registerService(StringService.class.getName(), ss, properties);
}
3.Bundle的开发实践
实践1、构建Utility类型的Bundle
该示例将第三方log4j工具包(版本为1.2.13)封装为OSGi Bundle组件。操作步骤如下:
•步骤一:在C盘根目录下创建名称为"org.apache.log4j"目录,将log4j.1.2.13.jar文件拷贝到该目录中;
•步骤二:在"org.apache.log4j"目录下构建META-INF目录,并在此目录下创建名称为"MANIFEST.MF"文件;
•步骤三:编辑"MANIFEST.MF"文件,在此文件中添加以下内容:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Apache Log4j
Bundle-SymbolicName: org.apache.log4j
Bundle-Version: 1.2.13
Bundle-ClassPath: .;log4j.1.2.13.jar
Export-Package: org.apache.log4j;version="1.2.13",
org.apache.log4j.config;version="1.2.13",
org.apache.log4j.helpers;version="1.2.13",
org.apache.log4j.jdbc;version="1.2.13",
org.apache.log4j.jmx;version="1.2.13",
org.apache.log4j.net;version="1.2.13",
org.apache.log4j.or;version="1.2.13",
org.apache.log4j.or.jms;version="1.2.13",
org.apache.log4j.or.sax;version="1.2.13",
org.apache.log4j.spi;version="1.2.13",
org.apache.log4j.varia;version="1.2.13",
org.apache.log4j.xml;version="1.2.13"
经过上述步骤后,名称为org.apache.log4j的OSGi Bundle已经构建完成。开发人员可以在其他Bundle中如同平常的开发模式一样引用Log4j的类包,获取Logger实例记录日志。
实践2、构建Service类型的Bundle
该示例Bundle由StringService接口,StringServiceImpl类和Activator类构成。该Bundle发布StringService接口服务,同时引用OSGi的标准LogService服务。
StringService接口是该示例Bundle发布的String服务实现接口。
package com.example;
public interface StringService {
String concat(String str1, String str2);
}
StringServiceImpl类是StringService接口的实现类,该类使用OSGi的标准LogService服务记录日志。
package com.example.internal;
import org.osgi.service.log.LogService;
import com.example.StringService;
public class StringServiceImpl implements StringService {
private LogService log;
public StringServiceImpl(LogService log) {
this.log = log;
}
public String concat(String str1, String str2) {
String str = str1 + str2;
if (log != null)
log.log(LogService.LOG_INFO, "Concat String Result is " + str);
return str;
}
}
Activator类为Bundle的生命周期入口,该类根据注入的BundleContext上下文获取OSGi LogService服务,然后注册StringService服务。
package com.example.internal;
import java.util.Hashtable;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.service.log.LogService;
import com.example.StringService;
public class Activator implements BundleActivator {
private LogService log;
public void start(BundleContext context) throws Exception {
//获取OSGi Log服务的服务引用
ServiceReference logSr = context.getServiceReference(LogService.class.getName());
//根据Log服务引用获取LogService服务实例
log = (LogService) context.getService(logSr);
//创建StringService接口服务实例
StringService ss = new StringServiceImpl(log);
//设定StringService的属性
Hashtable
//使用BundleContext注册发布StringService服务
context.registerService(StringService.class.getName(), ss, properties);
}
public void stop(BundleContext context) throws Exception {
}
}
Bundle的元数据清单如下:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Example Plug-in
Bundle-SymbolicName: com.example
Bundle-Version: 1.0.0
Bundle-Activator: com.example.internal.Activator
Bundle-Vendor: EGRID
Eclipse-LazyStart: true
Import-Package: org.osgi.framework;version="1.3.0",
org.osgi.service.log;version="1.3.0"
Export-Package: com.example
4. 结论
通过本文的探讨,开发人员可以明确在OSGi环境下进行Bundle开发时所要面临的一些决策及注意事项。下一篇文章我们将要详细探讨OSGi环境下Bundle编程的细节。本文中的点击此处下载。
分类: OSGi Architecture Design 2008-02-18 01:02 1286人阅读 评论(0) 收藏 举报
软件编程发展到今天可以看作是一个量变引发质变的过程。最初,程序开发面向过程,开发人员需要编写大量的过程代码,随着过程代码的不断积累(量变产 生),从代码维护和重用的角度,过程开发变得越来越不适应,质变产生,面向对象的开发逐渐被采用。由于面向对象的开发很好的封装了过程,而且从面向对象的 角度可以很好的描述实际应用中的需求模型,因此面向对象的开发逐渐成为主流。同样,随着面向对象开发的不断应用(量变产生),出现了大量的可复用的类及 包,维护这些类/包变得越来越困难,而且,尽管面向对象的编程机制可以很好的适应小规模应用的开发,但随着应用系统的规模越来越大,如同用细小的沙粒构建 堤坝,面向对象的机制难于适应,质变产生,面向组件的开发被引入开发过程。面向组件的开发目前仍可以认为是处于一种探索状态,目前还不存在一种统一的标准 可以遵循。
从另一个角度,历史是今天存在的基础,没有历史就没有今天。同样的道理,应用系统采用面向组件的开发实现,组件仍需要对象来构造,而对象在一定程度上是封 装的功能过程,三者相辅相成。不管是从上而下还是从下而上,应用系统需求模型在其实现过程中,系统设计者应该充分关注组件、对象和功能过程三个层面。
OSGi可以看作是面向组件开发的一种思路和基础环境。在OSGi环境中实现应用系统的需求模型要求开发人员对组件、对象开发具有充分的理解。衡量一个应 用系统实现好坏的标准之一是该系统是否是松耦合高内聚。面向对象的开发实现此目标的关键是接口/抽象的应用,OSGi面向组件的开发在此基础之上充分利用 了对象类包封装的机制。
1. Bundle的构建策略
通常,当我们构建应用系统时,我们需要充分重视所构建应用的业务需求模型即领域模型,同样的,在用软件代码实现业务需求模型时,我们也应当对软件系统的架 构模型给予充分的重视。采用OSGi技术实现应用系统时,展现在我们面前的将是一个个的Bundle组件,此时,我们必须首先弄清楚我们要构建什么样的 Bundle。
1.1 明确Bundle的构建需求及实现粒度
从需求模型的角度看,Bundle可以看作是需求模型中的一个功能模块实现,因此,在开发Bundle之前系统开发人员必须明确Bundle的功能需求。 需求模型中的功能模块的边界可大可小,同样,Bundle的实现粒度也是可大可小,极端情况下,小的Bundle可以仅实现一个微小的功能,大的 Bundle可以实现整个业务系统。
以记录日志为例,如果记录日志仅输出到控制台,则一个类就可以实现整个的功能,如果记录日志输出到数据库系统,则开发人员需要在整个功能用一个 Bundle实现,还是将日志记录功能和记录信息的数据库存储分为两个不同的Bundle实现,两个选择甚至更多的选择中做出决策。通常这个问题在现有的 软件开发方式中不需要过多的重视,但在OSGi开发中,开发人员必须根据需求确定Bundle的实现粒度。
1.2 确定Bundle的类型
我们在面向对象的系统开发过程中,经常会将一些通用的功能设计成为工具类,多个工具类封装为一个工具类包。由于OSGi开发建立在面向对象的开发之上, Bundle的开发也存在这种特点。OSGi开发的另一个特点是服务机制的引入,一个Bundle可以将其提供的功能发布成为一个或多个服务,供其他 Bundle查找使用。此外,建立在OSGi环境之上的组件开发也区别于通常的组件开发方式,因为我们可以利用OSGi环境提供的某些特性(参见下一节 充分利用OSGi环境的特性)。综上所述,我们可以将Bundle划分为如下几种类型(实际开发中,并不存在清晰的边界):
•Utility Bundle
这种Bundle与通常开发方式中的工具类或工具类包没有本质的区别,仅仅是将这些工具类发布到OSGi环境中,这些工具类也不依赖任何的OSGi环境或 特性。通常,这种Bundle特别适合目前存在的众多的第三方组件引入到OSGi环境中直接供OSGi开发人员使用。例如,我们可以将Apache开源项 目Log4j发布的工具包通过修改其META-INF目录下的MANIFEST.MF文件,添加Bundle的元数据信息就可以直接将其封装为可供 OSGi环境中其他Bundle使用的工具类Bundle。
•依赖OSGi特性的Bundle
这类Bundle可以被其他Bundle引用,为其提供功能,但是这类Bundle不能离开OSGi运行环境,否则不能使用。举例来说,一个提供数据缓存 功能的Bundle可能使用Bundle的数据存储区来缓存数据。Bundle的数据存储区的位置对Bundle开发者来说是透明的(参见下一节 充分利用OSGi环境的特性)。如果将该Bundle的数据缓存功能迁移到OSGi运行环境之外,则必须修改实现添加对缓存区位置的处理功能。
•引用和(或)发布OSGi服务的Bundle
这类Bundle也可以认为是依赖OSGi特性的Bundle,唯一的区别就是,该类Bundle充分利用的OSGi中服务的特性,引用其他Bundle 发布的服务和(或)向OSGi环境中发布自己的服务。OSGi环境提供的服务机制可以使得系统的实现遵循最大程度的松耦合。
1.3 隐藏Bundle的功能接口
组件开发除了应对系统的开发规模之外,其最重要的目标是降低系统耦合。开发人员采用OSGi Bundle开发时,应尽量屏蔽Bundle所提供功能的内部实现机制,仅将为其他Bundle提供的交互接口暴露出来。在OSGi中,这可以通过两种方 式,一种是通过Export供其他Bundle引用的类包;一种是向OSGi环境发布服务。
在Equinox中,Bundle内部实现的类包通常以"internal"标注,如org.eclipse.equinox.internal.cm.reliablefile。标注为"internal"的类包通常不包含在Export列表中,或者通过"x-internal"属性标记(该属性仅在Eclipse开发环境中提供)。
隐藏Bundle功能接口的一种良好机制是通过OSGi服务。开发人员仅将自己开发的Bundle的接口类包发布给其他Bundle可见,同时,将功能接 口的实现注册为OSGi中的服务,其他Bundle通过查找OSGi服务注册表获取该服务,通过服务的接口调用服务的功能。
1.4 尽可能应用OSGi提供的标准服务
OSGi联盟为一些经常用到的功能定义了标准服务,如应用程序管理服务,日志服务,事件服务,配置管理服务,用户管理服务,HTTP服务等等。如果开发人 员采用的OSGi环境提供了上述服务的实现,且这些服务实现满足系统的需求,则开发人员应尽可能使用这些服务,而不是为这些类似的功能定义自己的实现。
2.充分利用OSGi环境的特性
2.1 OSGi环境的动态特性
OSGi是一个动态的环境,OSGi运行环境内部状态的变化通过事件发布/监听机制进行交互。开发人员在构建Bundle时应充分利用OSGi环境的事件 监听机制。如,开发人员可以在自己的Bundle中注册Bundle事件的监听用来处理其他Bundle的安装,启动,停止,卸载等事件。
OSGi运行环境内部的事件主要包括三类:
•框架事件(FrameworkEvent)
STARTED 框架已经启动
ERROR 某个Bundle启动过程中引发错误
WARNING 某一Bundle引发一个警告
INFO 某一Bundle引发一个INFO类型的事件
PACKAGES_REFRESHED PackageAdmin.refreshPackage操作执行完成
STARTLEVEL_CHANGED StartLevel.setStartLevel操作执行完成
•Bundle事件(BundleEvent)
INSTALLED Bundle被安装到OSGi环境后系统发布该事件
RESOLVED Bundle被成功解析
LAZY_ACTIVATION Bundle将被延迟激活
STARTING Bundle正在被激活
STARTED Bundle被成功激活
STOPPING Bundle被停止
STOPPED Bundle正在被停止
UPDATED Bundle被更新
UNRESOLVED Bundle被UNRESOLVED
UNINSTALLED Bundle被卸载
•服务事件(ServiceEvent)
REGISTERED 服务被注册
MODIFIED 服务被修改
UNREGISTERING 服务正在被注销
关于上述事件的详细信息参考OSGi API文档。
下述代码展示了如何在Bundle组件中通过实现FrameworkListener,BundleListener和ServiceListener接口,并使用BundleContext注册监听OSGi环境的各种事件:
package com.example;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleListener;
import org.osgi.framework.FrameworkEvent;
import org.osgi.framework.FrameworkListener;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
public class Activator implements BundleActivator, FrameworkListener,
BundleListener, ServiceListener {
public void start(BundleContext context) throws Exception {
//注册监听
context.addFrameworkListener(this);
context.addBundleListener(this);
context.addServiceListener(this);
}
public void stop(BundleContext context) throws Exception {
}
//处理框架事件
public void frameworkEvent(FrameworkEvent event) {
if ((event.getType() & FrameworkEvent.ERROR) != 0) {
System.err.println("Framework ERROR: " + event.getBundle());
}
}
//处理Bundle事件
public void bundleChanged(BundleEvent event) {
if ((event.getType() & BundleEvent.STARTED) != 0) {
System.err.println("Bundle STARTED: " + event.getBundle());
} else if ((event.getType() & BundleEvent.STOPPED) != 0) {
System.err.println("Bundle STOPPED: " + event.getBundle());
}
}
//处理服务事件
public void serviceChanged(ServiceEvent event) {
if ((event.getType() & ServiceEvent.REGISTERED) != 0) {
System.err.println("Service REGISTERED: "
+ event.getServiceReference());
}
}
}
2.2 Bundle的生命周期及OSGi上下文特性
在Java虚拟机运行环境中,类的生命周期开始于虚拟机的加载,终止于被提前卸载或虚拟机停止,通常不需要开发人员干预。在OSGi环境中,开发人员可以参与Bundle的生命周期过程并能够获取Bundle在OSGi环境中运行的上下文。
通过实现org.osgi.framework.BundleActivator接口,并在Bundle的元数据头属性"Bundle- Activator"中指明该接口的实现类,如"Bundle-Activator: com.example.Activator"。当Bundle被启动或停止时,OSGi框架会将该Bundle的运行上下文BundleContext 注入到该实现类实例中,开发人员可以在该Bundle的运行过程中使用该上下文访问OSGi环境信息,访问OSGi环境中的其他Bundle,注册事件监 听,发布或引用服务等。
下面的代码片段展示了如何利用Bundle运行上下文与OSGi环境进行交互:
public void start(BundleContext context) throws Exception {
// 获取OSGi环境中的所有安装的bundle
for (Bundle bundle : context.getBundles()) {
System.out.println("Bundle Symbolic Name: "
+ bundle.getSymbolicName());
}
// 获取OSGi运行环境中的属性(查找范围包括系统属性)
System.out.println("osgi.framework = "
+ context.getProperty("osgi.framework"));
//注册其他Bundle
context.installBundle("file:C://test_bundle_1.0.0.jar");
//在该Bundle的数据存储区中构建datacache.file文件
context.getDataFile("datacache.file");
//注册监听
context.addFrameworkListener(this);
context.addBundleListener(this);
context.addServiceListener(this);
}
2.3 Bundle的资源管理特性
在通常的应用系统开发中,开发人员通常要考虑配置文件的存储路径,系统临时文件的存储路径等信息。由于OSGi环境中Bundle实际上是由一组文件资源 构成,开发人员在开发Bundle时可以充分利用这种特点,使用Bundle存储与Bundle相关的配置信息。OSGi环境在运行时为每一个 Bundle构建一个序列化数据存储区,开发人员可以使用该存储区存储Bundle在运行时生成的临时信息。
下述代码片段展示了如何通过Bundle提供的功能接口获取Bundle内部的资源:
•context.getBundle.getEntry("") 只查询Bundle内部资源,返回Bundle的URL,该URL与实现相关,如:bundleentry://256/
•context.getBundle.getEntry("/") 只查询Bundle内部资源,返回Bundle的URL,该URL与实现相关
•context.getBundle.getEntry("/build.properties") 只查询Bundle内部资源,返回Bundle内部build.properties文件的URL,该URL与实现相关,如:bundleentry://256/build.properties
•context.getBundle().getResource("build.properties") 使用Bundle的ClassLoader查询Bundle类域内的资源,如果Bundle不能被解析(RESOLVED),则只查询Bundle内部资源,返回Bundle内部build.properties文件的URL,该URL与实现相关。
开发人员在获取上述资源的URL后,可以转换成与Bundle运行系统相关的文件URL,如:file:C:/test_bundle_1.0.0。
下述代码片段展示了通过BundleContext接口获取Bundle运行时数据存储区资源:
•context.getDataFile("") 返回该Bundle的运行时数据存储区位置,如:E:/worksapce/.metadata/.plugins/org.eclipse.pde.core/CobWeb/org.eclipse.osgi/bundles/256/data
•context.getDataFile("config.xml") 返回该Bundle的运行时数据存储区内的config.xml文件,如果该文件不存在,则创建该文件。
2.4 面向服务的组件特性
OSGi的服务层提供了一个动态服务发布,绑定和查找模型,所谓的服务即指实现了某个(些)接口的Java对象。在面向对象的系统开发中,接口在分离系统的耦合方面扮演至关重要的角色,OSGi环境充分利用了这一点。
OSGi运行框架维护着一个服务注册表,Bundle可以通过Bundle上下文向该服务注册表中发布服务(只需指明服务实现的接口,服务的实例和服务的 属性),也可以使用Bundle上下文从服务注册表中根据接口名称及服务的属性查找其他Bundle注册的服务。在此模式下,Bundle之间的耦合关系 只存在接口层面,而与接口的实现无关。
下述代码片段展示了如何向OSGi服务注册表发布服务以及如何查找其他Bundle发布的服务:
public void start(BundleContext context) throws Exception {
//获取OSGi Log服务的服务引用
ServiceReference logSr = context.getServiceReference(LogService.class.getName());
//根据Log服务引用获取LogService服务实例
log = (LogService) context.getService(logSr);
//创建StringService接口服务实例
StringService ss = new StringServiceImpl(log);
//设定StringService的属性
Hashtable
//使用BundleContext注册发布StringService服务
context.registerService(StringService.class.getName(), ss, properties);
}
3.Bundle的开发实践
实践1、构建Utility类型的Bundle
该示例将第三方log4j工具包(版本为1.2.13)封装为OSGi Bundle组件。操作步骤如下:
•步骤一:在C盘根目录下创建名称为"org.apache.log4j"目录,将log4j.1.2.13.jar文件拷贝到该目录中;
•步骤二:在"org.apache.log4j"目录下构建META-INF目录,并在此目录下创建名称为"MANIFEST.MF"文件;
•步骤三:编辑"MANIFEST.MF"文件,在此文件中添加以下内容:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Apache Log4j
Bundle-SymbolicName: org.apache.log4j
Bundle-Version: 1.2.13
Bundle-ClassPath: .;log4j.1.2.13.jar
Export-Package: org.apache.log4j;version="1.2.13",
org.apache.log4j.config;version="1.2.13",
org.apache.log4j.helpers;version="1.2.13",
org.apache.log4j.jdbc;version="1.2.13",
org.apache.log4j.jmx;version="1.2.13",
org.apache.log4j.net;version="1.2.13",
org.apache.log4j.or;version="1.2.13",
org.apache.log4j.or.jms;version="1.2.13",
org.apache.log4j.or.sax;version="1.2.13",
org.apache.log4j.spi;version="1.2.13",
org.apache.log4j.varia;version="1.2.13",
org.apache.log4j.xml;version="1.2.13"
经过上述步骤后,名称为org.apache.log4j的OSGi Bundle已经构建完成。开发人员可以在其他Bundle中如同平常的开发模式一样引用Log4j的类包,获取Logger实例记录日志。
实践2、构建Service类型的Bundle
该示例Bundle由StringService接口,StringServiceImpl类和Activator类构成。该Bundle发布StringService接口服务,同时引用OSGi的标准LogService服务。
StringService接口是该示例Bundle发布的String服务实现接口。
package com.example;
public interface StringService {
String concat(String str1, String str2);
}
StringServiceImpl类是StringService接口的实现类,该类使用OSGi的标准LogService服务记录日志。
package com.example.internal;
import org.osgi.service.log.LogService;
import com.example.StringService;
public class StringServiceImpl implements StringService {
private LogService log;
public StringServiceImpl(LogService log) {
this.log = log;
}
public String concat(String str1, String str2) {
String str = str1 + str2;
if (log != null)
log.log(LogService.LOG_INFO, "Concat String Result is " + str);
return str;
}
}
Activator类为Bundle的生命周期入口,该类根据注入的BundleContext上下文获取OSGi LogService服务,然后注册StringService服务。
package com.example.internal;
import java.util.Hashtable;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.service.log.LogService;
import com.example.StringService;
public class Activator implements BundleActivator {
private LogService log;
public void start(BundleContext context) throws Exception {
//获取OSGi Log服务的服务引用
ServiceReference logSr = context.getServiceReference(LogService.class.getName());
//根据Log服务引用获取LogService服务实例
log = (LogService) context.getService(logSr);
//创建StringService接口服务实例
StringService ss = new StringServiceImpl(log);
//设定StringService的属性
Hashtable
//使用BundleContext注册发布StringService服务
context.registerService(StringService.class.getName(), ss, properties);
}
public void stop(BundleContext context) throws Exception {
}
}
Bundle的元数据清单如下:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Example Plug-in
Bundle-SymbolicName: com.example
Bundle-Version: 1.0.0
Bundle-Activator: com.example.internal.Activator
Bundle-Vendor: EGRID
Eclipse-LazyStart: true
Import-Package: org.osgi.framework;version="1.3.0",
org.osgi.service.log;version="1.3.0"
Export-Package: com.example
4. 结论
通过本文的探讨,开发人员可以明确在OSGi环境下进行Bundle开发时所要面临的一些决策及注意事项。下一篇文章我们将要详细探讨OSGi环境下Bundle编程的细节。本文中的点击此处下载。
发表评论
-
某osgi平台的uri
2012-06-19 19:06 01、http://localhost:9797/zcgl 2、 ... -
DWR与OSGi的整合
2011-12-30 21:56 1199DWR与OSGi的整合 最近一个项目中用了OSGi ... -
osgi常用链接
2011-12-30 21:54 9101、 http://dev.eclipse.org/viewc ... -
Extending Virgo with a HttpService
2011-12-30 21:52 1496Extending Virgo with a HttpServ ... -
jetty osgi 启动信息总结
2011-12-01 15:27 17501、运行java -jar -Dorg.osgi. ... -
(转)OSGI+Spring+Hibernate+...完美解决方案[非SpringDM] 2008-08-08
2011-11-24 14:30 1043OSGI+Spring+Hibernate+...完美 ... -
osgi 常用url
2011-11-12 17:15 9361、网络应用服务支撑运行平台 http://www.trust ... -
jetty in osgi ok
2011-11-02 18:04 11262011-11-2 17:29:13 org.springfr ... -
在spring osgi中取得datasource时出现问题
2011-11-02 15:06 1229在spring osgi中取得datasource时出现问题 ...
相关推荐
5. **安全控制**:OSGi提供了细粒度的安全模型,每个bundle都可以有自己的权限策略,增强了系统的安全性。 在实践中,OSGi的应用场景广泛,包括嵌入式系统、企业级应用服务器、设备管理系统等。学习OSGi的最佳实践...
OSGi(Open Services Gateway Initiative)...总的来说,掌握OSGi原理与最佳实践对于构建灵活、可扩展的Java应用至关重要。通过深入学习并实践这些内容,开发者可以提升系统设计能力,更好地应对复杂的企业级开发挑战。
7. **最佳实践**:提供在实际项目中应用OSGi的建议,如如何设计模块化的系统架构,如何进行测试和调试,以及性能优化策略。 《OSGi in Action》可能涵盖: 1. **实战指南**:通过实际案例,展示如何将OSGi应用于...
它是开发人员编程OSGi应用时的重要参考资源,可以查看具体方法的功能、参数和返回值,了解如何正确使用OSGi API来构建和管理模块。 通过这些学习资料,你可以全面掌握OSGi的基本概念、API使用以及最佳实践,进一步...
OSGi(Open Services Gateway Initiative)是一种Java模块化系统,它为开发人员提供了一种动态、模块化的...这些书籍通常会涵盖OSGi的配置、服务注册与查找、打包规范、安全策略以及如何在实际项目中集成OSGi等内容。
**OSGI原理与最佳实践** OSGI,全称为Open Service Gateway Initiative,中文可译为开放服务网关倡议,是一个用于创建动态模块系统的技术规范。它最初是为了家庭网络环境中的服务集成而设计,但随着时间的发展,...
- 通过学习这些示例,开发者可以快速掌握Spring OSGi的基本用法和最佳实践。 8. **Spring OSGi的应用场景** - 适用于大型分布式系统,允许按需加载和卸载服务,降低系统复杂性。 - 在企业级应用中,如EJB替代...
实践案例则可以帮助读者将理论知识应用到实际项目中,例如,如何创建和部署OSGi Bundle,如何使用OSGi的事件模型进行通信,以及如何利用Equinox的管理API进行系统监控和控制。 在最佳实践中,我们通常会学习如何...
8. **相关工具**:可能会提到一些辅助工具,如Apache Felix、Eclipse Equinox等OSGi实现,以及可能用到的构建工具(如Bnd或Maven的Bnd插件)来构建OSGi兼容的项目。 压缩包内的"OSGI 与Hibernate整合.docx"文件很...
OSGI(Open Services Gateway Initiative)是一种开放标准,用于创建模块化...通过阅读这本书,你可以获得对OSGI的全面认识,从理论到实践,从而在你的项目中更好地利用OSGI的优势,构建更加灵活、可维护的Java应用。
通过理解OSGI的基本原理和遵循最佳实践,开发者可以构建更灵活、可扩展且易于维护的Java应用程序。OSGI的广泛应用不仅限于服务器端,也可以用于桌面应用、嵌入式系统以及云计算环境,为现代软件开发提供了强大的模块...
OSGI(Open Service Gateway Initiative)是一种开放的框架,主要用于创建模块化、动态的Java应用...这本书的源代码是实践OSGI技术的重要资源,对于希望构建动态、模块化Java应用的开发者来说是一份宝贵的参考资料。
OSGi(Open Services ...学习和实践OSGi Web示例工程有助于理解如何在模块化环境中构建和管理复杂的Web应用,同时也可以提高软件的可维护性和可扩展性。如果你在搭建过程中遇到问题,记得留言讨论,以便获取更多帮助。
在实际开发中,理解OSGI核心概念并熟练使用Equinox Bundle可以帮助开发者构建更灵活、可扩展的应用程序。通过使用OSGI,可以实现组件的动态部署,允许在运行时添加、修改或移除功能,而不会影响到其他部分。这在大型...
OSGi是一种模块化系统,它允许Java应用程序以模块化的方式进行构建,提供了动态服务发现和依赖管理的能力。而Servlet容器,如Tomcat、Jetty等,是用于运行Web应用的地方,它们处理HTTP请求并调用相应的Servlet来响应...
在提供的压缩包文件名称“Tomcat-OSGi-QuickStart”中,"QuickStart"通常表示这是一个快速入门或示例项目,帮助用户快速理解和实践如何在Tomcat中配置和使用OSGi。这个压缩包可能包含了预配置的Tomcat服务器,示例...
OSGI(Open Services Gateway Initiative)是一种开放标准,用于创建模块化和可升级的Java应用程序。...正确理解和应用这些知识点,能帮助开发者构建出高效、灵活且易于维护的OSGI应用程序,实现数据库连接的无缝管理。
6. **安全模型**:OSGi提供了细粒度的安全控制,每个bundle都可以有自己的权限策略。 学习和使用OSGi,开发者可以实现更加灵活、可扩展和可维护的Java应用程序。通过掌握OSGi的核心原理和实践技巧,可以有效地管理...
- 模块系统:详述OSGi的包和类加载机制,以及如何定义和管理模块(也称为bundle)。 - 依赖管理:解释如何声明和解决模块间的依赖关系,确保正确地加载和启动服务。 - 动态性:介绍如何在运行时安装、启动、停止...
4. **WPF与OSGI的结合**:学习如何在WPF应用程序中嵌入OSGI框架,如何创建和管理OSGI bundle,以及如何通过WPF界面暴露和使用OSGI服务。 5. **动态性与可扩展性**:解释OSGI如何提供运行时的模块加载和卸载,使WPF...