打造一個基于OSGi的Web Application——設置初始化bundle的StartLevel
在前幾天的文章中描述了如何在Web Application中啟動OSGi,參見
工作原理是這樣的,首先,在原來存放初始化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,可以通過下面代碼獲得:
修改osgi.properties中關于org.osgi.framework.startlevel.beginning的配置項,我改成了5:
增加一個方法,用于安裝一個目錄下所有的直屬bundle,并且設置start level:
最后,遍歷start目錄下的子目錄來安裝所有的bundle:
最后,由于Declarative Services的存在,稍微調整了一下啟動策略,所有包含Service-Component的header定義的bundle,也調用start方法來啟動:
clean Server然后啟動Server,我們可以看到初始化后的bundle已經被賦予了指定Start Level。
附上initFramework方法的完整代碼,更多的代碼請參加以前的帖子:
打造一 個基于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:2 ServiceReference slRef = bundleContext.getServiceReference(StartLevel.class.getName());
3 StartLevel sl = slRef == null ? null : (StartLevel) bundleContext.getService(slRef);
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都能啟動。2 String bsl = bundleContext.getProperty("org.osgi.framework.startlevel.beginning");
3 if (bsl != null && isInteger(bsl)) sl.setInitialBundleStartLevel(Integer.parseInt(bsl));
修改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
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 }
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);
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 }
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 }
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 }
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