http://230996.blog.chinajavaworld.com/entry/3690/0/
在我们的上个部分,我们看了如何注册一个服务。现在哦我们需要从另外的Bundle查找并使用服务。
我们将问题放到我们的需求的上下文中,那个通过Martin Fowler的依赖反转的页面获得的灵感。我们建立了一个MovieFinder的服务并通过Service Registry注册了它。现在我们想要建立使用了MovieFinder的一个MovieLister来搜索定向的电影。我们假定MovieLister它自己将是被其它Bundle消费的一个服务,例如一个GUI应用程序。问题是,OSGi服务是动态的……它们来去都是动态的。意思就是有时我们想要调用MovieFinder服务但是它恰巧无效。
所以,如果MovieFinder没有呈现,那么MovieLister将做什么?显然,通过MovieLister完成工作的重要部分是调用MovieFinder,所以这有一些有用的选择给我们:
[list=decimal]
生成一个错误,例如返回null或者抛出一个异常
等待
在第一次里不要调用
[/list]
在这篇文章中我们将首先看前两项,它们十分简单。第三个选项可能甚至仍然没有什么感觉,但是看过前两个后你将会对它抱有希望。
第一件事我们需要为MovieLister服务定义接口。复制以下代码到osgitut/movies/MovieLister.java文件中:
1
2
3
4
5
6
7
|
package osgitut.movies;
import java.util.List;
public interface MovieLister {
List listByDirector(String name);
}
|
现在创建文件osgitut/movies/impl/MovieListerImpl.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
27
28
29
30
31
32
33
34
35
|
package osgitut.movies.impl;
import java.util.*;
import osgitut.movies.*;
import org.osgi.framework.*;
import org.osgi.util.tracker.ServiceTracker;
public class MovieListerImpl implements MovieLister {
private final ServiceTracker finderTrack;
public MovieListerImpl(ServiceTracker finderTrack) {
this.finderTrack = finderTrack;
}
public List listByDirector(String name) {
MovieFinder finder = (MovieFinder) finderTrack.getService();
if(finder == null) {
return null;
} else {
return doSearch(name, finder);
}
}
private List doSearch(String name, MovieFinder finder) {
Movie[] movies = finder.findAll();
List result = new LinkedList();
for (int i = 0; i < movies.length; i++) {
if(movies[i].getDirector().indexOf(name) > -1) {
result.add(movies[i]);
}
}
return result;
}
}
|
这可能是我们的目前最长的代码样本!那么这里将要做什么?首先你注意搜索电影的实际的逻辑被分隔在doSearch(String, MovieFinder)方法中,来帮助我们隔离OSGi具体代码。偶然的,我们执行搜索的方式是相当的愚笨和低效率,但是这不是这节指导的重点。我们无论如何只有两个电影在数据库中!
有趣的部分是在listByDirector(String name)方法中,使用了一个ServiceTracker对象来从Service Registry中获得MovieFinder。ServiceTracker是将最低级别的OSGi API中的大量令人不愉快的细节抽象出来的非常有用的类。然而我们仍然要检查服务是否确实存在。我们采取在我们的构造函数中传递给我们的ServiceTracker。
注意,你可能见过其他地方的代码从Registry获得一个服务而不使用ServiceTracker。例如,它可能调用BundleContext使用getServiceReference和getService。可是这个代码你不得不写的十分复杂并且它不得不小心的自行清理。以我所见,放到低级别的API中处理的益处很少,并且有很多的问题。总是单独使用ServiceTracker更好。
一个不错的创建ServiceTracker的地方是在Bundler的激活器中。复制这段代码到osgitut/movies/impl/MovieListerActivator.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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
package osgitut.movies.impl;
import java.util.*;
import org.osgi.framework.*;
import org.osgi.util.tracker.ServiceTracker;
import osgitut.movies.*;
public class MovieListerActivator implements BundleActivator {
private ServiceTracker finderTracker;
private ServiceRegistration listerReg;
public void start(BundleContext context) throws Exception {
// Create and open the MovieFinder ServiceTracker
finderTracker = new ServiceTracker(context, MovieFinder.class.getName(), null);
finderTracker.open();
// Create the MovieLister and register as a service
MovieLister lister = new MovieListerImpl(finderTracker);
listerReg = context.registerService(MovieLister.class.getName(), lister, null);
// Execute the sample search
doSampleSearch(lister);
}
public void stop(BundleContext context) throws Exception {
// Unregister the MovieLister service
listerReg.unregister();
// Close the MovieFinder ServiceTracker
finderTracker.close();
}
private void doSampleSearch(MovieLister lister) {
List movies = lister.listByDirector("Miyazaki");
if(movies == null) {
System.err.println("Could not retrieve movie list");
} else {
for (Iterator it = movies.iterator(); it.hasNext();) {
Movie movie = (Movie) it.next();
System.out.println("Title: " + movie.getTitle());
}
}
}
}
|
现在来看看这个激活器的启动。首先,在start方法中它创建了一个ServiceTracker对象,在我们刚写的MovieLister中使用。然后“打开”ServiceTracker告诉它启动跟踪Registry中MovieFinder服务的实例。之后,创建我们的MovieListerImpl对象并在Registry注册它到名为“MovieLister”的接口下。最后,为了在我们启动Bundle时看到有意思的事情,激活器靠MovieLister运行了一个简单的搜索并打印出结果。
我们需要建立并安装这个Bundle。我这次将不给出完整的介绍——你可以复习一下上个部分并使它工作。记得你需要创建一个manifest文件,并且它指示osgitut.movies.impl.MovieListerActivator类为Bundle-Activator。并且Import-Package行需要包含三个包,名称是org.osgi.framework,org.osgi.util.tracker和osgitut.movies。
一旦你已经安装了MovieLister.jar到Equinox运行时,你可以启动它。在那点上你将看到两条信息中的一条,依赖于是否这个BasicMovieFinder的Bundle在上一次一直在运行。如果它没有运行,你将看到:
1
2
|
osgi> start 2
Could not retrieve movie list
|
但是如果它正在运行你将看到:
1
2
|
osgi> start 2
Title: Spirited Away
|
通过停止和启动各个Bundle,你将能够显示任一信息。并且那些几乎是这部分的全部,除了记得我说过当一个服务无效时等待的事情?代码我们已经有了,这实际上是很琐碎的:简单的改变MovieListerImpl的16行来调用waitForService(5000)在ServiceTracker上代替getService(),并且添加try/catch块来捕捉InterruptedException。
listByDirector()方法等待5000毫秒的原因是要等MovieFinder服务被显示出来。如果一个MovieFinder服务那时已经安装了,当然,如果它已经存在——我们将立即获得它来使用。
通常,我们建议不要像这样挂起线程。特别在这种情况下,它可能很危险因为listByDirector()方法实际是从我们的Bundle激活器的start方法调用的,这是一个从框架线程调用的方法。
激活器意味着要迅速地返回,因为当一个Bundle启动了的时候会有一定数量的其它事情。事实上最坏的情况下我们可能引起死锁,因为我们会进入一个在属于框架对象的synchronized块,那可能已经被其他的一些给锁定了。通常的做法是从不在Bundle激活器的start方法中处理任何长时间运行或者阻塞操作,或者在框架直接调用的代码不做任何操作。
在下个部分中,我们将看看在使用应付神奇的第三个选项:“Don’t exist in the first place”。稍候!
分享到:
相关推荐
OSGi(Open Service Gateway Initiative)是一个Java社区定义的模块化服务平台,它允许在同一个运行环境中部署多个版本的同一个组件,而不会相互冲突,从而提供了一个动态的、模块化的运行时环境。OSGi规范定义了...
学习OSGI入门和整合Spring,对于开发复杂的企业级应用,或者想要提升系统灵活性和可维护性的开发者来说,是非常有价值的。通过理解OSGI的模块化机制和Spring的依赖注入原理,可以构建出更加高效和可扩展的Java应用。
创建一个服务接口,实现该接口的提供者捆绑,并在消费者捆绑中通过 OSGi 服务注册表查找并使用该服务。 ### 7. 进阶话题 深入学习 Spring OSGi,可以研究安全性、远程服务、事件处理、事务管理等高级特性。同时,...
实例代码部分通常会包含实际的OSGI应用示例,比如如何创建一个简单的服务提供者和消费者,或者展示如何在OSGI环境中实现AOP(面向切面编程)。通过这些例子,你可以更直观地理解OSGI的工作原理,并学会在项目中应用...
OSGi,全称为 Open Service Gateway Initiative,从字面上理解,它最初被设计为一个面向服务的平台。1999 年,OSGi 联盟成立,旨在为通过网络向设备提供服务建立开放的标准。该联盟的目标是构建一个在广域网和局域网...
OSGi(Open Service Gateway Initiative)是一种Java模块化系统,它允许开发者创建可热更新、可隔离且互相依赖管理的模块。Spring OSGi是Spring框架与OSGi服务的结合,使得在OSGi环境中使用Spring变得简单。本教程将...
OSGI框架由一组称为"bundle"的模块组成,每个bundle都是一个自包含的Java程序单元,包含类、资源以及元数据。这些bundle可以通过导出和导入包来声明它们提供的服务和依赖的服务。这种模块化设计使得开发者能够轻松地...
在这个压缩包中,我们可以找到一个名为"OSGI介绍"的文件,它可能包含了OSGI的基本概念、核心特性以及如何开始学习OSGI的相关知识。 首先,OSGI的核心概念是模块系统。在OSGI框架中,每个模块被称为服务单元或bundle...
- **服务(Services)**:服务是bundle之间通信的接口,一个bundle可以提供服务(Export),其他bundle则可以消费这些服务(Import)。服务通过Service Registry进行注册和查找,使得服务发现和使用变得简单。 **...
OSGi为Java应用提供了一个动态、模块化的运行时环境,使得软件组件可以独立地加载、卸载和更新,而不影响整个系统的运行。 在OSGi环境中实现Web服务,可以极大地提高灵活性和可维护性。Web服务是一种通过网络(通常...
在OSGi环境中,一个服务可以被其他bundle消费。在`server` bundle中,可能会定义一个公开接口,供其他bundle通过服务注册和查找机制进行交互。这涉及到OSGi框架的核心组件,如BundleContext和ServiceRegistry,它们...
Spring框架是一个强大的轻量级Java应用程序框架,而OSGi则是一种模块化系统,用于管理和部署Java应用程序。在Spring OSGi中,Spring的应用组件可以作为OSGi服务来发布和消费,从而实现更灵活、可插拔的架构。 标题...
3. **osgi入门图解.pptx** - 这份PPT可能包含了一套逐步的OSGI入门教程,通过图表和示例帮助初学者理解OSGI的基本概念,比如bundle的结构、配置、依赖关系以及如何构建和运行一个简单的OSGI应用。这种视觉化的学习...
OSGI服务器的核心是Equinox,这是Eclipse项目的一个组成部分,常用于桌面应用和RCP(Rich Client Platform)应用。随着技术的发展,Equinox逐渐被引入到移动设备和手持设备上,而"OSGI Server"项目则旨在消除在...
Gemini Blueprint是OSGi联盟企业专家组(EE Expert Group)开发的一个服务,它提供了对Spring应用上下文在OSGi环境中的支持,使得开发者可以使用Spring的声明式编程模型来编写OSGi服务。 在描述中提到的博文链接,...
其中Equinox是Eclipse基金会开发的一个OSGI框架的实现,而Oscar和Knopflerfish也是OSGI社区较为知名的实现。这些框架为OSGI在不同应用场景中的部署和运行提供了基础。 文档中还介绍了OSGI的R4规范,这是OSGI技术的...
首先,"Getting Started with OSGi 1 Your First Bundle.pdf"是入门篇,讲解了如何创建你的第一个OSGi捆绑包(Bundle)。捆绑包是OSGi的基本模块单位,包含了可执行的Java代码和其他资源。开发者需要了解如何定义...