osgi container是java实践中的一个框架,在这个框架中,按照osgi的规范,实现了java中module的思想,从而真正实现了java的模块化开发。
在模块的互用方面,osgi提供了两种方式:一是通过export/import包实现,二是通过在osgi bundlecontext中注册service,实现各个模块之间的交互。第二种方式符合SOA的标准,是osgi中推荐的交互方式。同样的,osgi container和传统的java 进程交互,也提供了同样的方式,在《在osgi容器外应用osgi bundle提供的服务》一文中,分析了如何在osgi container外部,引用osgi服务的一种方式,同样的在osgi bundle中引用传统java进行的服务,也是通过osgi container的bundleContext实现的。
下面是实现在osgi bundle中访问一个外部的service的完整的过程。
一、在osgi container中注册一个外部的服务(这个例子实在Apache的felix container中完成)
在felix的host对象中,首先实例化一个felix对象,然后,初始化felix,随后在felix container的bundlecontext中注册一个服务
m_felix = new Felix(config);
m_felix.init();
AutoProcessor.process(config, m_felix.getBundleContext());
m_felix.getBundleContext().registerService(ShareInterface.class.getName(), new ShareImpl(), null);
// Now start Felix instance.
m_felix.start();
二、在bundle中引用这个注册的服务
虽然这个服务已经注册到osgi container的bundlecontext中了,但是在bundle中利用正常的ServiceTracker无法引用到这个服务(可能是由于注册时,不在osgi container中,所以,没有在osgi的整个环境中出现),但是,这个服务在system bundle中是可见的,所以,可以通过访问system bundle的bundlecontext来获得这个外部的服务
Bundle[] bundles = context.getBundles();
ServiceTracker st = new ServiceTracker(bundles[0].getBundleContext(),ShareInterface.class.getName(),null);
st.open();
Object si = st.getService();
Method m = si.getClass().getDeclaredMethod("share", null);
m.invoke(si, null);
同样的,由于服务注册时,不在osgi container的环境中,所以服务实例化的classloader和osgi container中的classloader之间不能够直接的访问,利用反射的方法,可以访问到注册的服务,就实现了osgi bundle访问osgi container之外的服务了。