隨筆 - 19, 文章 - 1, 評論 - 21, 引用 - 0
          數據加載中……

          打造一個基于OSGi的Web Application——設置初始化bundle的StartLevel

          在前幾天的文章中描述了如何在Web Application中啟動OSGi,參見

          打造一 個基于OSGi的Web Application——在WebApplication中啟動OSGi

          后來發現其中在初始化時加載bundle的方式,還有一些美中不足。這種方式加載的bundle都具有相同的啟動順序,即bundle的初始化默認start level,在之前均沒有做過特別的設置,所以默認值都是1,這樣會導致所有的bundle的啟動順序無法控制,在某些希望特殊bundle優先加載的場合(如日志功能,需要最先加載),我們希望能夠在bundle初始化的時候就能指定特別的start level,這樣所有的bundle就能按照我們預設的啟動順序來加載了。下面就是我優化過的初始化代碼,能夠解決啟動順序問題。

          工作原理是這樣的,首先,在原來存放初始化bundle的目錄,也就是OSGi-Web工程的/WEB-INF/osgi/plugins目錄下面再增加一個名為start的目錄,在start目錄下,再按照期望設置的start level來建立子目錄,例如,期望設置start level為1的bundle,放到plugins/start/1目錄下面;期望設置start level為2的bundle,放到plugins/start/2目錄下面,以此類推。

          代碼方面,設置bundle的start level,需要使用StartLevel Service,可以通過下面代碼獲得:
          1                 // StartLevel Service,用于設置bundle的startlevel
          2                 ServiceReference slRef = bundleContext.getServiceReference(StartLevel.class.getName());
          3                 StartLevel sl = slRef == null ? null : (StartLevel) bundleContext.getService(slRef);
          然后設置initial bundle start level:
          1                 // 設置新bundle的初始startlevel為系統配置項:org.osgi.framework.startlevel.beginning的值
          2                 String bsl = bundleContext.getProperty("org.osgi.framework.startlevel.beginning");
          3                 if (bsl != null && isInteger(bsl)) sl.setInitialBundleStartLevel(Integer.parseInt(bsl));
          這樣所有新安裝的bundle的初始化start level都將被設置為和系統配置項:org.osgi.framework.startlevel.beginning相同的值,以確保所有默認安裝的bundle都能啟動。
          修改osgi.properties中關于org.osgi.framework.startlevel.beginning的配置項,我改成了5:
          1 #Specifies the beginning start level of the framework. See Start
          2 #Level Service Specification on page 235 for more information.
          3 #
          4 org.osgi.framework.startlevel.beginning = 5


          增加一個方法,用于安裝一個目錄下所有的直屬bundle,并且設置start level:
           1     private static void installBundles(BundleContext bundleContext, File bundleRoot, StartLevel sl, int bsl) {
           2         File bundleFiles[] = bundleRoot.listFiles(new FilenameFilter() {
           3             public boolean accept(File dir, String name) {
           4                 return name.endsWith(".jar");
           5             }
           6         });
           7 
           8         if (bundleFiles != null && bundleFiles.length > 0) {
           9             for (File bundleFile : bundleFiles) {
          10                 try {
          11                     Bundle bundle = bundleContext.installBundle(bundleFile.toURL().toExternalForm());
          12                     if (sl != null && bsl > 0) sl.setBundleStartLevel(bundle, bsl);
          13                     if (logger.isInfoEnabled()) logger.info("Install bundle success: " + bundleFile.getName());
          14                 } catch (Throwable e) {
          15                     if (logger.isWarnEnabled()) logger.warn("Install bundle error: " + bundleFile, e);
          16                 }
          17             }
          18         }
          19     }

          最后,遍歷start目錄下的子目錄來安裝所有的bundle:
           1                 // 安裝bundle并設置相應的start level
           2                 File slRoot = new File(bundleRoot, "start");
           3                 if (slRoot.isDirectory()) {
           4                     File slDirs[] = slRoot.listFiles(new FileFilter() {
           5                         public boolean accept(File file) {
           6                             return file.isDirectory() && isInteger(file.getName());
           7                         }
           8                     });
           9 
          10                     for (File slDir : slDirs) {
          11                         installBundles(bundleContext, slDir, sl, Integer.parseInt(slDir.getName()));
          12                     }
          13                 }
          14 
          15                 // 安裝直屬目錄下面的bundle
          16                 installBundles(bundleContext, bundleRoot, sl, 0);

          1     private static boolean isInteger(String value) {
          2         try {
          3             Integer.parseInt(value);
          4             return true;
          5         } catch (NumberFormatException e) {
          6             return false;
          7         }
          8     }

          最后,由于Declarative Services的存在,稍微調整了一下啟動策略,所有包含Service-Component的header定義的bundle,也調用start方法來啟動:
           1                 for (Bundle bundle : bundleContext.getBundles()) {
           2                     if (bundle.getState() == Bundle.INSTALLED || bundle.getState() == Bundle.RESOLVED) {
           3                         if (bundle.getHeaders().get(Constants.BUNDLE_ACTIVATOR) != null || bundle.getHeaders().get("Service-Component"!= null) {
           4                             try {
           5                                 bundle.start(Bundle.START_ACTIVATION_POLICY);
           6                                 if (logger.isInfoEnabled()) logger.info("Start bundle: " + bundle);
           7                             } catch (Throwable e) {
           8                                 if (logger.isWarnEnabled()) logger.warn("Start bundle error: " + bundle, e);
           9                             }
          10                         }
          11                     }
          12                 }

          clean Server然后啟動Server,我們可以看到初始化后的bundle已經被賦予了指定Start Level。


          附上initFramework方法的完整代碼,更多的代碼請參加以前的帖子:
           1     // 初始化Framework環境
           2     private static void initFramework(Framework framework, ServletContextEvent event) throws IOException {
           3         BundleContext bundleContext = framework.getBundleContext();
           4         ServletContext servletContext = event.getServletContext();
           5 
           6         // 將ServletContext注冊為服務
           7         registerContext(bundleContext, servletContext);
           8 
           9         File file = bundleContext.getDataFile(".init");
          10         if (!file.isFile()) { // 第一次初始化
          11             if (logger.isInfoEnabled()) logger.info("Init Framework");
          12 
          13             String pluginLocation = servletContext.getInitParameter(CONTEXT_PARAM_OSGI_PLUGINS_LOCATION);
          14             if (pluginLocation == null) pluginLocation = DEFAULT_OSGI_PLUGINS_LOCATION;
          15             else if (!pluginLocation.startsWith("/")) pluginLocation = "/".concat(pluginLocation);
          16 
          17             // 安裝bundle
          18             File bundleRoot = new File(servletContext.getRealPath(pluginLocation));
          19             if (bundleRoot.isDirectory()) {
          20                 if (logger.isInfoEnabled()) logger.info("Load Framework bundles from: " + pluginLocation);
          21 
          22                 // StartLevel Service,用于設置bundle的startlevel
          23                 ServiceReference slRef = bundleContext.getServiceReference(StartLevel.class.getName());
          24                 StartLevel sl = slRef == null ? null : (StartLevel) bundleContext.getService(slRef);
          25                 // 設置新bundle的初始startlevel為系統配置項:org.osgi.framework.startlevel.beginning的值
          26                 String bsl = bundleContext.getProperty("org.osgi.framework.startlevel.beginning");
          27                 if (bsl != null && isInteger(bsl)) sl.setInitialBundleStartLevel(Integer.parseInt(bsl));
          28 
          29                 // 安裝bundle并設置相應的start level
          30                 File slRoot = new File(bundleRoot, "start");
          31                 if (slRoot.isDirectory()) {
          32                     File slDirs[] = slRoot.listFiles(new FileFilter() {
          33                         public boolean accept(File file) {
          34                             return file.isDirectory() && isInteger(file.getName());
          35                         }
          36                     });
          37 
          38                     for (File slDir : slDirs) {
          39                         installBundles(bundleContext, slDir, sl, Integer.parseInt(slDir.getName()));
          40                     }
          41                 }
          42 
          43                 // 安裝直屬目錄下面的bundle
          44                 installBundles(bundleContext, bundleRoot, sl, 0);
          45 
          46                 for (Bundle bundle : bundleContext.getBundles()) {
          47                     if (bundle.getState() == Bundle.INSTALLED || bundle.getState() == Bundle.RESOLVED) {
          48                         if (bundle.getHeaders().get(Constants.BUNDLE_ACTIVATOR) != null || bundle.getHeaders().get("Service-Component"!= null) {
          49                             try {
          50                                 bundle.start(Bundle.START_ACTIVATION_POLICY);
          51                                 if (logger.isInfoEnabled()) logger.info("Start bundle: " + bundle);
          52                             } catch (Throwable e) {
          53                                 if (logger.isWarnEnabled()) logger.warn("Start bundle error: " + bundle, e);
          54                             }
          55                         }
          56                     }
          57                 }
          58 
          59                 if (slRef != null) bundleContext.ungetService(slRef);
          60             }
          61 
          62             new FileWriter(file).close();
          63             if (logger.isInfoEnabled()) logger.info("Framework inited.");
          64         }
          65     }

          posted on 2010-03-29 15:26 dbstar 閱讀(3699) 評論(0)  編輯  收藏 所屬分類: OSGi

          主站蜘蛛池模板: 灌云县| 宿迁市| 宁安市| 亚东县| 韩城市| 金寨县| 闵行区| 建水县| 辽宁省| 南川市| 永年县| 望城县| 穆棱市| 视频| 淮安市| 石泉县| 吉水县| 葫芦岛市| 泰安市| 宾川县| 南漳县| 凌海市| 东平县| 铜梁县| 平塘县| 洪洞县| 达尔| 襄垣县| 武义县| 靖远县| 依兰县| 多伦县| 辽源市| 陵水| 那坡县| 都江堰市| 汤阴县| 于田县| 资源县| 通辽市| 丹阳市|