随笔 - 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 阅读(3686) 评论(0)  编辑  收藏 所属分类: OSGi


只有注册用户登录后才能发表评论。


网站导航: