《OSGI原理与最佳实践》一书中已经给出了基本的方式,这里在林昊的基础上增添几行代码完成一个可用的例子:
1 首先建立几个插件工程,并导出成插件包,这里将导出的插件包统一放置到G://osgi_prj//system_bundle目录下
2 建立java project,并写一个带main方法的类,用于启动OSGI以及先前的插件
源码:
public class StartOsgi { private static BundleContext context = null; /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { String osgiBundles = "org.eclipse.osgi.services_3.2.0.v20090520-1800.jar@start,javax.servlet_2.5.0.v200806031605.jar@start,cxf-dosgi-ri-singlebundle-distribution-1.2.jar@start" + ",DatabasePlugin_1.0.0.jar@start,BasePlugin_1.0.0.jar@start,MessagePlugin_1.0.0.jar@start"; // 配置Equinox的启动 FrameworkProperties.setProperty("osgi.noShutdown", "true"); FrameworkProperties.setProperty("eclipse.ignoreApp", "true"); FrameworkProperties.setProperty("osgi.bundles.defaultStartLevel", "4"); FrameworkProperties.setProperty("osgi.bundles", osgiBundles); // 根据需要设置bundle所在的路径 String bundlePath = "G://osgi_prj//system_bundle"; // 指定需要加载的plugins所在的目录 FrameworkProperties.setProperty("osgi.syspath", bundlePath); // 调用EclipseStarter,完成容器的启动,指定configuration目录 EclipseStarter.run(new String[] { "-configuration", "configuration", "-console" }, null); // 通过EclipeStarter获取到BundleContext context = EclipseStarter.getSystemBundleContext(); Object obj = getOSGiService(MsgService.class.getName()); Class<?> cls = getBundleClass("MessagePlugin", MsgService.class.getName()); Method m = cls.getMethod("findByProperty", new Class[] {String.class, Object.class}); List list = (List) m.invoke(obj, new Object[] {"id", 2}); System.out.println(list.get(0).toString()); Messege msg = new Messege(); msg.setFrom(10); msg.setTo(10); msg.setTitle("ttttt"); msg.setContent("6666"); msg.setIsRead(1); msg.setReadDate(new Timestamp(new Date().getTime())); msg.setSendDate(new Timestamp(new Date().getTime())); msg.setSubjectId("111"); msg.setCompanyId(4); Method m2 = cls.getMethod("add", new Class[] {String.class}); m2.invoke(obj, JsonConvertor.obj2string(msg)); } public static Object getOSGiService(String serviceName){ ServiceReference serviceRef=context.getServiceReference(serviceName); if(serviceRef==null) return null; return context.getService(serviceRef); } /** * 获取OSGi容器中插件的类 */ public static Class<?> getBundleClass(String bundleName,String className) throws Exception{ Bundle[] bundles=context.getBundles(); for (int i = 0; i < bundles.length; i++) { if(bundleName.equalsIgnoreCase(bundles[i].getSymbolicName())){ return bundles[i].loadClass(className); } } return null; }
3 运行便可以看到调用到了osgi的内部类方法
说明:osgi里面的bundle是通过自己的classloader加载内部类,所以只能通过反射进入指定bundle获取class,而不能将包导入调用工程中,这里也可以看到findbyproperty方法只能返回不带类型的List,如果换成List<Message>将会出错,因为调用工程与插件的class不一样。