OSGI学习之二: HelloWorld
不可免俗,一律HelloWorld!
因为OSGI有三层,module,lifecycle,service,所以我们用三个helloworld来演示三个层。
1.Module Layer:
Module层没有代码要写,只是将代码打包到bundle。
比如,我们要将下边这个类放到bundle里。
package org.foo.hello; public class Greeting { final String m_name; public Greeting(String name) { m_name = name; } public void sayHello() { System.out.println("Hello, " + m_name + "!"); } }
将这个类导出到org.foo.hello.jar,并在这个jar的META-INF/MANIFEST.MF文件里添加
Bundle-ManifestVersion: 2
Bundle-Name: Greeting API
Bundle-SymbolicName: org.foo.hello
Bundle-Version: 1.0
Export-Package: org.foo.hello;version="1.0"
对于想要使用上边创建的这个bundle的bundle,需要在它的jar包的META-INF/MANIFEST.MF里添加
Bundle-ManifestVersion: 2
Bundle-Name: Greeting Client
Bundle-SymbolicName: org.foo.hello.client
Bundle-Version: 1.0
Import-Package: org.foo.hello;version="[1.0,2.0)"
可以看到一个是export,一个是import。
2.Lifecycle层
如果一个bundle需要做一些初始化工作,比如连接数据库,这时lifecycle层就有用武之地了。Bundles可以顶一个 activator,这个可以让我们介入到一个bundle的生命周期里。这个后来会详细再说,现在先看看这货大概怎么工作。下边这个是一个单例模式的greeting类。
package org.foo.hello; public class Greeting { static Greeting instance; final String m_name; Greeting(String name) { m_name = name; } public static Greeting get() { return instance; } public void sayHello() { System.out.println("Hello, " + m_name + "!"); } }
它在使用前需要调用构造函数来初始化name参数。我们看一下如何利用activator来初始化:
package org.foo.hello; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; public class Activator implements BundleActivator { public void start(BundleContext ctx) { Greeting.instance = new Greeting("lifecycle"); } public void stop(BundleContext ctx) { Greeting.instance = null; } }
start和stop都是接口BundleActivator的方法,还有方法的参数BundleContext,是一个重要的参数,后面会详细讲,这货就是你的bundle和整个OSGI系统交互用的。
这个例子就是让你知道一个bundle可以介入自己的lifecycle,而且可以和整个OSGI framework交互。
另外你需要在你的META-INF/MANIFEST.IM里加上
Bundle-Activator: org.foo.hello.Activator
Import-Package: org.osgi.framework
这样OSGI framework就知道你有了自己的activator了。
3.Service层
service层是基于接口的实现方式,比如
接口:
package org.foo.hello; public interface Greeting { void sayHello(); }
OK,下边是实现
package org.foo.hello.impl; import org.foo.hello.Greeting; public class GreetingImpl implements Greeting { final String m_name; GreetingImpl(String name) { m_name = name; } public void sayHello() { System.out.println("Hello, " + m_name + "!"); } }
没啥嘛,这个OSGI有个毛关系,别急,只要你平时就是面向接口编程的。改动不大,要做的就是如何注册你的服务到OSGI,和怎样从OSGI查询已经注册的服务。
所有的服务实现最终都被打包到一个bundle里,这个bundle必须添加自己的lifecycle响应以有机会注册自己的服务。就是说你必须实现自己的activator。LOOK:
package org.foo.hello.impl; import org.foo.hello.Greeting; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; public class Activator implements BundleActivator { public void start(BundleContext ctx) { ctx.registerService(Greeting.class.getName(), new GreetingImpl("service"), null); } public void stop(BundleContext ctx) {} }
看看在start方法里都干了些什么?bunldecontext,注册服务,第一个参数服务实现的接口名,接着是服务实现的实例,最后是service property。
stop的时候OSGI会帮你注销任何这个bundle注册的服务。
这是注册一个服务,那么怎么查找一个服务呢?
package org.foo.hello.client; import org.foo.hello.Greeting; import org.osgi.framework.*; public class Client implements BundleActivator { public void start(BundleContext ctx) { ServiceReference ref = ctx.getServiceReference(Greeting.class.getName()); ((Greeting) ctx.getService(ref)).sayHello(); } public void stop(BundleContext ctx) {} }
好了就这样,这里没有考虑找不到服务的情况。
这里我们可以看到得到一个service分两步,第一步是获取一个service的reference。用这个reference再去得服务。
这个是因为service可以随时被注销,你直接引用阻止jvm的垃圾回收。