===== 作用 =====
- 应用内模块的隔离
- 一个模块一个服务,一个服务的变更不影响其他服务(主要是二方库依赖)
===== 隔离原理 =====
bundle间之所以能隔离,因为每个bundle都有一个单的ClassLoader,且该ClassLoader的 parent ClassLoader为空(也就是说不会委派给其他ClassLoader)。但是每个bundle加载Import-Package时,会使用Export-Package的ClassLoader去加载。这也就保证了不同bundle间也可以共享类
===== 运行方式 =====
- all bundle模式:所有逻辑都以bundle的方式存在
- embedded 模式:在主应用中启动一个osgi框架 + 其他bundle
本文主要讲解embedded 模式 的使用
===== bundle间的调用 =====
bundle间服务调用的方式 (主程序也是作为一个bundle来工作的)
==== 通过反射调用 ====
- bundle-service注册服务,bundle-cliet获取服务
- 根据方法名,反射调用方法
优点
* 简单无依赖
==== 通过共享接口调用 ====
* bundle-client bundle-server之间依赖同一个二方库(二方库中定义了服务的接口),bundle-server实现服务,bundle-client调用服务
缺点:
* 实现复杂
- 接口要单独一二方库,被2个bundle依赖 (bundle-client mvn依赖的scope=provided)
- 配置bundle-server 暴露package
- 配置bundle-server 引入package
===== 样例代码 =====
=== bundle mvn配置 ===
org.apache.felix
org.apache.felix.framework
6.0.3
org.apache.felix
maven-bundle-plugin
true
${project.version}
$(replace;${project.artifactId};-;_)
aa.bb.cc.intf;version="${project.version}"
org.osgi.framework
aa.bb.cc.impl.App
=== bundle中注册服务 ===
public class App implements BundleActivator {
private static BundleContext context;
static BundleContext getContext() {
return context;
}
@Override
public void start(BundleContext bundleContext) throws Exception {
System.out.println("start bundle -- " + bundleContext);
App.context = bundleContext;
Hashtable props = new Hashtable();
props.put("Language", "English");
context.registerService(IHello.class.getName(), new DefaultHelloServiceImpl(), props);
}
@Override
public void stop(BundleContext bundleContext) throws Exception {
App.context = null;
System.out.println("end bundle");
}
public class DefaultHelloServiceImpl implements IHello {
@Override
public String say() {
return "Hello osgi,service";
}
}
}
=== 主程序中通过反射调用服务 ===
public static void main(String[] args) {
try {
final Map configMap = new HashMap();
configMap.put(Constants.FRAMEWORK_STORAGE_CLEAN, "onFirstInit");
Felix felix = new Felix(configMap);
felix.init();
final BundleContext context = felix.getBundleContext();
// 加载一个bundle
Bundle bundle = context.installBundle("file:/Users/fangqiang/Documents/osgibundle/server/target/server-1.0-SNAPSHOT.jar");
// 启动bundle
bundle.start();
// 启动osgi框架
felix.start();
// 通过反的方法调用bundle中的服务
for (ServiceReference> registeredService : bundle.getRegisteredServices()) {
Object service = context.getService(registeredService);
Method say = service.getClass().getMethod("say");
System.out.println(say.invoke(service));
}
} catch (Exception ex) {
System.exit(0);
}
}
=== 主程序中通过共享接口调用 ===
public static void main(String[] args) {
try {
final Map configMap = new HashMap();
configMap.put(Constants.FRAMEWORK_STORAGE_CLEAN, "onFirstInit");
// 程序中通过configMap配置要暴露的包 (如果是bundle中直接在pom.xml中的Export-Package中配置即可)
configMap.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, "aa.bb.common.intf; version=1.0.0.SNAPSHOT");
HostActivator activator = new HostActivator();
// 将主程序中的服务注册到osgi中 (如果没有服务要暴露给bundle,则不需要该配置)
configMap.put(FelixConstants.SYSTEMBUNDLE_ACTIVATORS_PROP, Arrays.asList(activator));
Felix felix = new Felix(configMap);
felix.init();
BundleContext context = felix.getBundleContext();
// 加载一个bundle
Bundle bundle = context.installBundle("file:/Users/fangqiang/Documents/osgibundle/server/target/server-1.0-SNAPSHOT.jar");
// 启动bundle
bundle.start();
// 启动osgi框架
felix.start();
// 通过接口调用bundle中服
System.out.println(((IHello1)context.getService(context.getServiceReference(IHello1.class.getName()))).say());
} catch (Exception ex) {
System.exit(0);
}
}
=== 其他bundle中通过共享接口调用 ===
public class App implements BundleActivator {
@Override
public void start(BundleContext ctx) {
System.out.println("----------------hello client start---------------------");
ServiceReference ref = ctx.getServiceReference(IHello.class.getName());
IHello hello = (IHello) ctx.getService(ref);
hello.say();
System.out.println("----------------hello client start---------------------");
}
@Override
public void stop(BundleContext ctx) throws Exception {
}
}