Example4 已经能够应对服务的动态可用性问题,但是其处理过于复杂,于是 OSGI 规范提出了 Service Tracker 的概念以解决 Example4 中出现的问题,Service Tacker 翻译过来的意思就是“服务追踪者”的信息,其作用类似于 Java 中的 TCP 服务器,当服务端开始监听接口的时候,则当前线程会停止,直至发现有客户端请求连接该端口为才会继续执行下面的代码。 而 ServiceTracker 则是监听符合特定筛选条件的服务,当 ServiceTacker 开启之后,如果没有任何符合筛选条件的服务被发现,则会抛出 org.osgi.framework.BundleException,具体使用示例如下:
/*
* Apache Felix OSGi tutorial.
**/
package tutorial.example5;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;
import tutorial.example2.service.DictionaryService;
/**
* 使用 ServiceTacker 重构 Example4 例子。
**/
public class Activator implements BundleActivator
{
// Bundle's context.
private BundleContext m_context = null;
// The service tacker object.
private ServiceTracker m_tracker = null;
/**
* Implements BundleActivator.start(). Crates a service
* tracker to monitor dictionary services and starts its "word
* checking loop". It will not be able to check any words until
* the service tracker find a dictionary service; any discovered
* dictionary service will be automatically used by the client.
* It reads words from standard input and checks for their
* existence in the discovered dictionary.
* (NOTE: It is very bad practice to use the calling thread
* to perform a lengthy process like this; this is only done
* for the purpose of the tutorial.)
* @param context the framework context for the bundle.
**/
public void start(BundleContext context) throws Exception
{
m_context = context;
// Create a service tracker to monitor dictionary services.
m_tracker = new ServiceTracker(
m_context,
m_context.createFilter(
"(&(objectClass=" + DictionaryService.class.getName() + ")" +
"(Language=*))"),
null);
System.out.println("wait DictionaryService...");
m_tracker.open();
try
{
System.out.println("Enter a blank line to exit.");
String word = "";
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
// Loop endlessly.
while (true)
{
// Ask the user to enter a word.
System.out.print("Enter word: ");
word = in.readLine();
// Get the selected dictionary service, if available.
DictionaryService dictionary = (DictionaryService) m_tracker.getService();
// If the user entered a blank line, then
// exit the loop.
if (word.length() == 0)
{
break;
}
// If there is no dictionary, then say so.
else if (dictionary == null)
{
System.out.println("No dictionary available.");
}
// Otherwise print whether the word is correct or not.
else if (dictionary.checkWord(word))
{
System.out.println("Correct.");
}
else
{
System.out.println("Incorrect.");
}
}
} catch (Exception ex) { }
}
/**
* Implements BundleActivator.stop(). Does nothing since
* the framework will automatically unget any used services.
* @param context the framework context for the bundle.
**/
public void stop(BundleContext context)
{
}
}
构建 manifest.mf
Bundle-Name: Service Tracker-based dictionary client
Bundle-Description: A dictionary client using the Service Tracker.
Bundle-Vendor: Apache Felix
Bundle-Version: 1.0.0
Bundle-Activator: tutorial.example5.Activator
Import-Package: org.osgi.framework,
org.osgi.util.tracker,
tutorial.example2.service
编译、打包:
D:\devInstall\apache\felix-framework-6.0.0\examples\demo05\src> javac -cp ..\..\demo02\target\example2.jar;..\..\..\bin\felix.jar -encoding UTF-8 -d ../target tutorial\example5\*.java
D:\devInstall\apache\felix-framework-6.0.0\examples\demo05\src> cd ../target
D:\devInstall\apache\felix-framework-6.0.0\examples\demo05\src> cp ../src/manifest.mf ./
D:\devInstall\apache\felix-framework-6.0.0\examples\demo05\src> jar cvfm example4.jar manifest.mf -C . .
已添加清单
正在添加: manifest.mf(输入 = 311) (输出 = 183)(压缩了 41%)
正在添加: tutorial/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: tutorial/example5/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: tutorial/example5/Activator.class(输入 = 2132) (输出 = 1174)(压缩了 44%)
安装、运行:
g! lb 16:58:41
START LEVEL 1
ID|State |Level|Name
0|Active | 0|System Bundle (6.0.0)|6.0.0
1|Active | 1|jansi (1.17.1)|1.17.1
2|Active | 1|JLine Bundle (3.7.0)|3.7.0
3|Active | 1|Apache Felix Bundle Repository (2.0.10)|2.0.10
4|Active | 1|Apache Felix Gogo Command (1.0.2)|1.0.2
5|Active | 1|Apache Felix Gogo JLine Shell (1.1.0)|1.1.0
6|Active | 1|Apache Felix Gogo Runtime (1.1.0)|1.1.0
7|Active | 1|Service listener example (1.0.0)|1.0.0
g! install file:./examples/demo05/target/example5.jar
Bundle ID: 16
g! start 16
org.osgi.framework.BundleException: Unable to resolve [16](R 16.0): missing requirement [[16](R 16.0)] osgi.wiring.package; (osgi.wiring.package=tutorial.example2.service) Unresolved requirements: [[[16](R 16.0)] osgi.wiring.package; (osgi.wiring.package=tutorial.example2.service)]
g! install file:./examples/demo02/target/example2.jar 16:47:46
Bundle ID: 17
g! start 17 16:52:06
Ex1: Service of type tutorial.example2.service.DictionaryService registered.
g! start 16 16:52:10
wait DictionaryService...
Enter a blank line to exit.
Enter word:
上面再安装 example5.jar 的之前,首先将前面注册的 DictionaryService 全部取消注册,方法是直接全部卸载掉,然后安装 example5.jar,启动发现启动失败,原因是依赖的服务 DictionaryService 没有被注册, 安装 example2.jar, 注册了一个 English Service,则启动 example5.jar 成功。