我的懒毛病又开始犯了……一定要克服,坚持!
-------------------------
原始地址:http://www.eclipsezone.com/eclipse/forums/t90688.html
原作者: Neil Bartlett
--------------------------
OSGi 起步(4): 注册服务
欢迎回到Eclipse Zone的OSGi教程。我们终于要开始讲服务了。在我看来,服务层是OSGi中最有意思的一部分,所以接下来的几篇文章将很有意思。
上一次,我们看了关于MovieFinder接口的例子,它将被MovieLister用来查找电影。事实上,你可以注意到这个例子来自Martin Fowler著名的论文”依赖注入(Dependency Injection)”(http://www.martinfowler.com/articles/injection.html),也被称为”Inversion of Control”或者IoC(控制倒置?)。
首先回忆一下IoC期望解决的问题。对于MovieLister,一般来说,它并不关心电影记录的原始数据是从哪里来的,所以我们用MovieFinder接口隐藏了这些细节。由于MovieLister只依赖于接口,而不是接口的具体实现,所以我们可以为之提供MovieFinder的不同实现,比如有的是从数据库中获取数据,有的则是通过调用Amazon网络服务接口获取数据。
到目前为止,一切都很顺利,但是我们还需要给MovieLister提供一个MovieFinder的具体实现。我们通过外部容器把一个合适的对象“推”给MovieLister,而不是让它自己去调用某个特定的查找方法。这就是所谓的“控制倒置”。现在已经很多种容器被开发出来,比如PicoContainer,HiveMind,Spring,以及EJB3.0。但是,到目前为止,这些容器都存在着一个缺陷:他们大多是静态的。一旦MovieLister获得MovieFinder,这种联系就会在JVM(JAVA虚拟机)的整个生命期中被保持。
OSGi同样实现了IoC模式,但是是以动态的方式实现。它使得,动态地为MovieLister提供MovieFinder的实现,并能在需要时动态卸载,成为一种可能。这样,我们可以实现“热交换”,比如把一个从纯文本文件中寻找电影数据的应用替换成从Amazon网络服务查找数据的应用。
OSGi的服务层帮我们实现了这种可能。简单来说,首先,我们将一个MovieFinder在服务注册表里注册成一个服务;然后,这个MovieFinder服务被提供给MovieLister。一个服务,其实只是一个Java对象(POJO),当然如果你愿意,也可以说它是以Java接口的名义注册的(POJI)。
首先,我们来看看如何注册一个服务。然后,我们将看到怎么从注册表中获得服务并提供给MovieLister。
我们讲要把上次创建的BasicMovieFinder bundle注册成服务。我们并不需要对现有的类进行修改,只需要添加一个bundle activator(控制器?)。复制以下内容到 osgitut/movies/impl/BasicMovieFinderActivator.java :
import org.osgi.framework. * ;
import osgitut.movies. * ;
import java.util.Properties;
import java.util.Dictionary;
public class BasicMovieFinderActivator implements BundleActivator {
private ServiceRegistration registration;
public void start(BundleContext context) {
MovieFinder finder = new BasicMovieFinderImpl();
Dictionary props = new Properties();
props.put("category", "misc");
registration = context.registerService(
MovieFinder.class.getName(),
finder, props);
}
public void stop(BundleContext context) {
registration.unregister();
}
}
然后将BasicMovieFinder.mf的内容替换为:
Bundle-ManifestVersion: 2
Bundle-Name: Basic Movie Finder
Bundle-SymbolicName: BasicMovieFinder
Bundle-Version: 1.0.0
Bundle-Activator: osgitut.movies.impl.BasicMovieFinderActivator
Import-Package: org.osgi.framework ,
osgitut.movies ; version="[1.0.0,2.0.0)"
跟上一次相比,增加了两样内容。首先是,Bundle-Activator行,它告诉框架bundle的activator是哪个(这个我们上一次没有用到)。另外,还增加了一个导入package,org.osgi.framework。上一个版本的bundle因为不需要与框架进行交互,所以它不需要导入OSGi API package。
重新创建BasicMovieFinder.jar:
jar cfm BasicMovieFinder.jar BasicMovieFinder.mf osgitut/movies/impl/*.class
现在回到OSGi的控制台,应该能看到上一次安装的BasicMovieFinder.jar。所以,我们只需要告诉OSGi更新这个bundle,输入命令update N。这个N是这个bundle的ID(通过输入命令ss可以得到)。启动bundle,你将看到……几乎什么都没有发生。(译者-_-!)
事实上,我们只是在OSGi服务注册表例注册了第一个服务。但是,不幸的是,在“另一端”不存在任何对象。所以,并没有任何可见的内容被看见。如果想要确定我们的代码是否真的起效果了,我们需要进一步深入研究,输入以下命令:
我们将看到以下输出:
Registered by bundle: file:BasicMovieFinder.jar [ 4 ]
No bundles using service.
太棒了,这表示我们的服务注册成功了。我很想继续下去,告诉你们怎么去查找服务和在其它的bundle中使用它,不过,这些得等到明天再讲了。你可以看看通过services还能做些什么。对于初学者而言,试试输入不带参数的services吧(它的参数是为了显示我们需要的服务的过滤器),你将看到所有已经注册的服务列表。这个数目是相当庞大。