欢迎回来EclipseZone OSGi迷你系列。终于,我们准备接触Services了。我认为,Service层是OSGi最精彩的部分,所以接下来的部分将会很有趣。
上一次我们看了MovieFinder接口的例子,我们讲了将使用MovieLister搜索影片。事实上你可以认为这个例子——它从Martin Fowler的著名页上的"依赖注入",也正如所知道的"反转控制"(Inversion of Control)或IoC。
重新用IoC来尝试解决这个问题。一个MovieLister并不特别关心原始电影数据的出处,所以我们使用MovieFinder接口来从它隐藏细节。思想是我们可以代替MovieFinder的任一细节,比如获取数据库或者甚至调用一个Amazon Web Service,既MoiveLister仅仅依赖于这个接口,不是任意具体实现。
到目前为止一切顺利,但是在一些点上,我们必须确实给一个具体的MovieFinder到MovieLister的实现。与其让MovieLister到外面去调用一个查找方法,不如我们用一个外部的容器"推"一个合适的对象给它。因此这个成为反转控制。不少这样的容器已经被开发出来了,例如PicoContainer,HiveMind,Spring甚至是EJB3.0。可是所有这些容器都有一个限制:它们大多是静态的。一旦一个MovieFinder给予了一个MovieLister,它就相当于JVM的生命期。
OSGi也允许我们实现IoC模式,但是在动态方法中。它可能动态的提供MovieFinder的实现给MovieLister并在之后移除它们。接下来,我们能够做到在一个文本文件查找电影的应用程序到使用Amazon Web Services的查找它们的热交换。
这就是服务层帮我们做的。十分简单,我们注册一个MovieFinder服务到Service Regisgry中。之后MovieLister可以用那个MovieFinder服务被提供出来。一个服务因此不比一个Java对象——POJO多些什么——并且它被注册在Java接口的名称下面(一个POJI?)。
这次,我们将这是看看使用registry来注册服务。稍后,我们看看如何获得这个registry外的服务并提供一个MovieLister。
我们将添加上次我们建立的BasicMovieFinder的Bundle。我们不需要修改已存在的类,我们仅仅需要添加一个Bundle的激活器。所以复制以下代码到osgitut/movies/impl/BasicMovieFinderActivator.java文件中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | package osgitut.movies.impl;
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的内容:
1 2 3 4 5 6 7 8 | Manifest-Version: 1.0 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)" |
自从上一次以来,有两个信息被添加到这个manifest。第一个是Bundle-Activator行,它告诉框架关于我们的Bundle的新激活器——我们上次没有用到它。同样,我添加了org.osgi.framework到这个导入到包。正如我们的Bundle的上版本不能同框架交互,它不需要导入这个OSGi API包。
现在你可以重新建立BasicMovieFinder.jar文件:
1 2 | > javac -classpath equinox.jar:MoviesInterface.jar osgitut/movies/impl/*.java > jar cfm BasicMovieFinder.jar BasicMovieFinder.mf osgitut/movies/impl/*.class |
回到OSGi控制台,你将看到上次的BasicMovieFinder.jar仍然被安装着。那么你只需要通过输入update N来告诉OSGi去更新这个Bundle,这个N是Bundle的数字标识(你用ss命令找到的那个)。现在使用start N来启动Bundle并且你会看见……很小的事情发生了。
事实上,我们仅仅用OSGi Service Registry注册了我们第一个服务,但是可惜的是没有人在"另一端",所以这个注册不能产生任何可视化的影响。如果我们想要亲自保证我们的代码实际做了些什么,我们将继续挖掘,并且我们可以使用以下命令:
1 | services (objectClass=*MovieFinder) |
我们将看到以下输出:
1 2 3 | {osgitut.movies.MovieFinder}={category=misc, service.id=22} Registered by bundle: file:BasicMovieFinder.jar [4] No bundles using service. |
很好,我们的服务被注册了,并且我很想继续告诉你如何查找服务并在其他的Bundle中使用它,但是那将在另外一天了。在这期间,看看你可以用services命令做些什么。开始时常是输入没有任何表达式的services,之后——那确实可以通过服务的过滤仅仅显示器中的一个。不使用过滤,你将看到所有的注册了的服务。有着令人惊讶的巨大数字。
参考:
没有评论:
发表评论