主题
企业架构
服务器端 OSGI 简介
页面: 1, 2, 3
OSGi环境提供了必要的黑盒来利用如前所述的许多特性。我此时选择使用黑盒这个词是因为环境的创建完全由OSGi供应商/提供者负责,Java EE容器也由供应商以大体上相同的方式负责。开发人员或架构师唯一要关心的就是理解OSGi内部的部署和编程模型,它们同样能够跨您所选择的任何OSGi环境使用,这一点与Java EE具有惊人的相似之处。
对于已经从Java EE容器迁移到Spring等轻量级框架的用户,也不要因为Java EE容器和OSGi之间最新的比较关系而气馁。事实上,一些相关的工作正在进行之中,以便集成OSGi与Spring的功能。随着本文的深入,您会发现您的Spring项目也会从OSGi中受益。在OSGi中,环境、实现、运行时、容器和框架这些术语经常交替使用,这是经过考虑的。当这些专门词汇经常用来指由OSGi供应商/提供者分发的软件的同一部分时,请保持开放的心态。
开始探索OSGi环境之后,您可能会惊讶地发现同样的环境不仅能够适用于智能电话等小型设备,也能够在桌面应用程序管理和服务器端项目中应用。其原因是OSGi部署和编程模型同样可以应用于所有这些不同的情况中,这就引入了OSGi最具体的部分:程序包。领会程序包的概念是理解OSGi的关键,因为作为开发人员或架构师,您将时常要直接处理它。这里有个实际的例子,可用来简要说明程序包的概念。
程序包是OSGi使用的封装格式,也常称作模块,它包含了Java类和资源以及其他OSGi底层环境使用的处理指令——封装的结构与JAR文件的结构非常相似。这就产生了一个问题:“如果OSGi程序包的封装方式与JAR文件一样,那它为何如此特殊呢?”或者还可以这样问:“到底为什么要遵照OSGi程序包的JAR格式重新封装现有的所有应用程序的JAR文件呢?”

当它推出时,通过传统的Java类路径还不能获得OSGi程序包的JAR文件——或者简单地说,是OSGi模块(Java类和其他应用程序资源)——的内容。它们被委托给OSGi环境,后者会创建一种针对在自身部署的每一个OSGi程序包JAR文件所含全部底层类和资源之间的依赖关系解析的类装载器图。
类装载器图的这个概念的特殊性有几个原因。其一,它限制了应用程序执行时在任一单个点装载的Java类和资源的数量。另外,依靠图模型,OSGi环境中运行的任何应用程序都能够根据需要自动创建、合并或销毁分支以满足类的依赖关系,给在开始所提到的动态安装、启动、中止、更新和卸载的功能让路。同样重要的是,因为OSGi程序包由普通的Java类和资源组成,所以OSGi环境对于底层应用程序逻辑是不可知的,因此您可能遇到的OSGi程序包范围很广,从Eclipse IDE插件、XML语法分析器、基于控制台的应用程序、servlet到其他一些变量。
了解了这一背景之后,我们来看一下实际的OSGi程序包。由于本文是OSGi程序包的介绍,这里给出的例子将尽可能的精简。但通过这些例子,可以试着外推这些相同的原则如何应用于企业空间中更完善的程序包,比如Logging包、Servlet或其他变量。
我们现在要创建的程序包被设计成飞行运输服务,其他OSGi程序包可以轮流使用它获得某城市的座位可用性。
package intro.carrier;
import java.util.Properties;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceEvent;
import intro.carrier.service.FlightService;
/**
* This class implements a simple bundle that uses the bundle
* context to register international flight availability service
* with the OSGi framework. The flight service interface is
* defined in a separate class file and is implemented by an
* inner class.
**/
public class Activator implements BundleActivator
{
/**
* Implements BundleActivator.start(). Registers an
* instance of a flight service using the bundle context;
* attaches properties to the service that can be queried
* when performing a service look-up.
* @param context the framework context for the bundle.
**/
public void start(BundleContext context)
{
Properties props = new Properties();
props.put("Seating", "International");
context.registerService(
FlightService.class.getName(), new FlightImpl(), props);
}
/**
* Implements BundleActivator.stop(). Does nothing since
* the framework will automatically unregister any registered services.
* @param context the framework context for the bundle.
**/
public void stop(BundleContext context)
{
// NOTE: The service is automatically unregistered.
}
/**
* A private inner class that implements a flight service;
* see FlightService for details of the service.
**/
private static class FlightImpl implements FlightService
{
// The set of cities contained in the flight service
String[] c_flight =
{"mexico city", "paris", "london", "sao paulo", "toronto"};
/**
* Implements FlightService.checkAvailability(). Determines
* if the passed in city is available
* @param flight the flight to be checked.
* @return true if the flight seating is available,
* false otherwise.
**/
public boolean checkAvaiability(String flight)
{
flight = flight.toLowerCase();
for (int i = 0; i < c_flight.length; i++)
{
if (c_flight[i].startsWith(flight))
{
return true;
}
}
return false;
}
}
}
首先,我们引入了许多org.osgi.framework类,它们几乎是每一个OSGi程序包的要素。接着,我们声明了两个initial方法,它们也是OSGi的关键组件:start和stop。顾名思义,从底层环境调用这两个方法对OSGi程序包或者进行注册,或者进行注销。剩余的代码是一个纵切的内部类,作为服务逻辑。没有什么复杂的——只是几个为我们的目的服务的硬编码的值和一个在下面这个接口上的依赖关系:
package intro.carrier.service;
/**
* A simple service interface that defines a flight service.
* A flight service simply verifies the existence of seating.
**/
public interface FlightService
{
/**
* Check for the availability of a flight.
* @param flight the flight to be checked.
* @return true if the flight seating is available,
* false otherwise.
**/
public boolean checkAvailability(String flight);
}
就Java代码而言,这些就已经完成了。现在,我们来举例说明需要伴随前面的Java类的OSGi描述符:
Bundle-Name: International Flights Bundle-Description: A bundle that registers International Flight service Bundle-Vendor: Apache Felix Bundle-Version: 1.0.0 Bundle-Activator: intro.carrier.Activator Export-Package: intro.carrier.service Import-Package: org.osgi.framework
这些名称和描述参数是自解释的。Bundle-Vendor参数指出为了进行部署将要使用的OSGi实现,此处指的是名为Felix的Apache Software Foundation的OSGi实现。Bundle-Version域只是表示我们的第一个程序包迭代1.0.0。
应当注意一下剩余的域。Bundle-Activator指出包含实际的激活逻辑的类——start和stop方法——而Export-Package指出程序包中的哪些包将对于其他OSGi程序包可用。此处,我们表明我们的服务包是可以访问的。最后,Import-Package用来指出为了成功部署程序包而需要装载的依赖关系。
Java代码编译采用和所有其他Java源文件一样的方式完成,只要OSGi实现在编译类路径中可用,而使用Java SE包含的标准jar工具就可以进行OSGi程序包的实际创建。最终封装的OSGi程序包将拥有如下面清单所给出的一个目录结构:
+-|
|
+-META-INF-+
| |+MANIFEST.MF
|
|
+-intro/carrier-+
| |+Activator$1.class
| |+Activator$FlightImpl.class
| |+Activator.class
|
|
+-intro/carrier/service-+
|+FlightService.class
该过程有些冗长和机械,所以我们不会举例说明我们的介绍性的应用程序中所用的剩余的程序包。您可以查阅该示例下载代码,它包括一个自动构建脚本,使大量示例OSGi程序包的创建变得容易。好消息是封装OSGi程序包几乎总是一次完成,就像JAR文件;大多数情况下,这会由第三方提供者来完成。还有就是,目前已经有一些大型OSGi程序包库可以提供从JMX和RMI到XMLRPC的一切东西,它们对于您的项目都是现成可用的。 Oscar Bundle Repository就是其中之一。
您既然已经理解了OSGi程序包,我们就来使用程序包实际运行和部署一个应用程序。
|
页面: 1, 2, 3 |
下一页 » |