在前几天的文章中描述了如何在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 }
分享到:
相关推荐
9. Web 应用 bundle:Web 应用 bundle 是一个基于 OSGi 和 Spring 的 Web 应用程序,能够提供更加强大的灵活性和可靠性。 本文通过一个简单实例,介绍了如何利用 Spring-DM 开发基于 OSGi 和 Spring 架构的 Web ...
在本文中,我们将深入探讨如何基于VirgoServer进行Spring Osgi Web开发,这是一个涉及OSGi容器、Spring框架和Web应用程序的集成技术。首先,我们需要确保拥有正确的开发环境和工具,包括Spring Tool Suite (STS),...
Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化构建工具,它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,比传统的XML更加简洁明了。利用Gradle打包项目,可以实现自动化、高效管理项目依赖...
在基于OSGi和Spring开发Web应用中,OSGi(Open Services Gateway Initiative)是一个开放标准,用于创建模块化Java应用程序。它允许开发者将应用程序分解为独立的模块,称为bundle,每个bundle都包含自己的类路径、...
dmServer,全称为Dynamic Modules Server,是一个完全模块化的Java服务器,其基于OSGi,专为运行企业级Java应用和Spring应用而设计。dmServer的模块化特性使得它能够提供更加灵活和可靠的部署环境,对于那些需要频繁...
本示例以“基于OSGI的Web开发例子”为主题,主要介绍了如何利用Equinox框架在OSGi环境中进行Web应用的开发,通过一个简单的“Hello World”项目来展示其工作原理。 首先,我们需要理解Equinox。Equinox是Eclipse...
Web Bundle允许开发者将一个传统的WAR(Web Application Archive)文件打包成OSGi Bundle,从而在OSGi环境中运行。这使得Web应用可以像普通OSGi服务一样被动态加载、卸载和更新,提高了系统的可维护性和可扩展性。 ...
本文深入浅出地解释了如何结合Felix和Struts2构建基于OSGi的Web应用,通过一个具体的时间服务示例展示了OSGi的动态部署和模块化特性。这种开发方式使得Web应用的维护和扩展更为灵活,适应性强,尤其适合需要长期运行...
为了验证基于OSGi框架和插件设计模式结合构建的轻量级动态化系统的可行性和有效性,可以通过一个具体的项目实例来进行验证。例如,可以构建一个企业级应用平台,该平台具备基本的功能模块,并支持通过插件形式扩展新...
通过以上步骤,我们可以构建一个基于OSGi和Spring的企业级Web应用。这种组合不仅能够提升应用的可维护性和可扩展性,还能极大地提高开发效率和系统的稳定性。 综上所述,将OSGi和Spring结合起来使用,可以有效地...
Web Application Bundle (WAB) 是一种特殊的OSGi Bundle,它可以作为一个Web应用运行。WAB包含传统的Web项目元素,如Web-INF目录和web.xml,同时还包含OSGi元数据,如MANIFEST.MF文件,使得它们能够作为OSGi模块运行...
Web示例工程是使用OSGi技术构建的一个具体应用,通常包括了如何在OSGi环境中部署和运行Web应用程序的实例。 在OSGi框架中,Equinox是Eclipse基金会提供的一个实现,它是OSGi规范的主要实现之一,广泛应用于服务器端...
本项目结合了Struts2和Felix1.4,构建了一个基于OSGI的Web基础设施,提供了灵活和可扩展的框架来开发Web应用。 在OSGI环境中,应用被分解为小型的、独立的模块,称为bundle。每个bundle包含一组相关的类和资源,...
**背景:** OSGi (Open Service Gateway Initiative) 是一种模块化容器,它允许Java应用程序以模块化的形式组织起来,每个模块被称为一个“bundle”。OSGi不仅支持模块化编程,还支持热部署和动态配置等功能,非常...
标题"基于EQUINOX的OSGI BUNDLE运行例子"指的是一个实际操作示例,展示了如何在EQUINOX OSGi环境中运行OSGi Bundle。EQUINOX提供了一个完整的运行时环境,使得开发者可以方便地管理和执行这些模块化的Bundle。 描述...
4. **模块化开发**:在 OSGi 中,每个组件(bundle)都是一个独立的单元,有自己的类路径和生命周期。这使得组件之间可以解耦,便于维护和更新。 5. **服务注册与发现**:OSGi 通过服务注册表提供服务发现机制,...
开发者需要在Sample中定义 Bundle Activator,它是Bundle启动和停止时执行的入口点,用于初始化和清理资源。此外,还可能包含配置元数据,如MANIFEST.MF文件,用于指定Bundle的依赖、导出和导入的包。 接下来是...