基于OSGi的企业级开发框架实践——全局参数工具
2013-02-27 11:19
344 查看
在接下去的几篇文章中,我们将通过一些最佳实践来继续讨论我们的开发框架。做为一个应用系统,全局参数配置是一个不可或缺的重要工具。它可以为系统初始化提供必须的参数,也可以为系统提供一些用户自定义的个性化参数,总之它关系到整个应用系统的正确运行。在上一篇文章中,我们已经认识了它,现在就让我们更加深入的了解它的庐山真面目。当你启动了开发框架的运行时环境后,会在Eclipse Console中看到如下图所示的日志信息:
(图一)
在开发框架运行时容器启动的时候会自动的加载指定目录下的system.properties文件,该文件就是默认的全局参数配置文件,比如上例中的D:\home\admin\share\data\helloworld\system.properties。在assembly目录下提供了一个system.properties文件的默认模板,请在第一次启动开发框架时复制该文件到指定的目录,比如上例中的D:\home\admin\share\data\helloworld目录,否则就会看到如上一篇文章中所介绍的异常信息。下图展示了system.properties文件提供的默认配置内容:
(图二)system.properties内容
该文件中定义了一些默认的全局参数,比如:应用程序的工作目录路径,服务器的ID标识,数据库驱动配置等(开发框架支持MySQL的Master/Slave模式的配置,从上图中就可以看到,我们配置了2个数据库的URL参数,后续文章将对数据库相关操作进行详细的讨论)。当然你也可以添加自定义的参数,只要符合Java属性文件的格式即可。接下去让我们来看看全局配置参数加载器是如何工作的。请在Eclipse IDE中打开core-platform Bundle的bundle-context-osgi.xml文件,如下图所示:
(图三)
开发框架提供了一个OSGi的服务定义,org.storevm.eosgi.properties.loader.SystemPropertiesLoader,该服务用于在Bundle启动时加载system.properties属性文件。另外该服务还有一个“location”属性,用于定义system.properties文件的路径(如果路径中不提供文件名,则使用默认的system.properties做为文件名)。现在我们的全局参数已经全部被加载了,接下去我们将在程序中读取这些全局参数。
请打开biz-share Bundle中的bundle-context-osgi.xml配置文件,如下图所示:
(图四)
在该文件中开发框架提供了全局配置参数加载器服务的引入配置,如下代码:
该配置将core-platform Bundle中发布的OSGi服务引入到biz-share Bundle中,这样在biz-share Bundle中就可以使用这个OSGi服务了,请看bundle-context.xml配置文件中的代码,如下:
前2个配置是关于OSGi的annotation配置,下一章我们将对此进行详细讨论,这里我们暂时忽略它。第三个bean配置是我们经常用到的Spring的占位符替换的Bean。它依赖于我们的全局配置参数加载器服务的Bean。只有当PropertiesLoader服务实例化之后PropertyPlaceholderConfigurer才会进行实例化,这样,我们就可以在Spring XML中使用如下的配置了:
其中用${}表示的占位符就是配置在system.properties文件中的属性值。
这里可能会有人提出疑问,PropertyPlaceholderConfigurer不是也提供了一个locations属性值用于指定属性配置文件的路径吗?是的,但是这里存在一个问题,PropertyPlaceholderConfigurer只能读取本Bundle中的*.properties文件,如果其他Bundle要读取相同的参数值,则需要在其他Bundle中重新再定义一个相同的*.properties文件,这是由OSGi的Classloader隔离机制所导致的,而且属性文件被打包到Bundle中,我们就失去了在运行时修改配置参数的灵活性,所以开发框架提供了一个单独的OSGi服务用于加载全局的配置参数,这样所有的Bundle只要引入该OSGi服务就能读取统一的配置参数了。以下代码展示了如何在代码中使用PropertiesLoader服务:
从代码中我们可以看到,在readProperties方法中我们读取了“share.data.path”配置参数,从图二中我们可以看到share.data.path的参数值。由于我们使用了annotation,所以无需再在spring的配置文件中注册bean。在我们的开发框架中,所有bean的配置均使用annotation完成。好了,我们可以启动Eclipse中的OSGi运行时容器了,点击工具栏上的运行按钮,并选择“helloworld”,如下图所示:
(图五)
Console中会显示大量的启动日志信息,如果运行正常,你将会看到如下图所示的信息,表示我们的测试成功了:
(图六)
从上图可知,程序读取的“share.data.path”配置参数值和我们在system.properties文件中配置的值完全一样。目前我们使用的是开发框架提供的运行时环境来进行代码测试,后续文章我们将介绍开发框架提供的另外一种集成测试方法。
接下来我们将在OSGi容器的运行过程中,修改system.properties中的参数值,然后看看,在biz-share Bundel中是否读取到了修改之后的新值。
请在Console中输入“ss”命令,然后会列出所有的Bundle,如下图所示:
(图七)
我们查找core-platform和biz-share Bundle的id值,如下图所示(可能你的id与图中的不一样,以实际情况为准):
(图八)
从上图可以看到,biz-share Bundle的id是116,而core-platform Bundle的id是118。我们修改system.properties文件中的“share.data.path”配置项,如下图:
(图九)
我们在Console中的“osgi>”提示符下继续输入如下命令:
该命令将停止core-platform Bunlde的运行,在Console中会显示如下提示信息(由于篇幅关系,这里的提示信息进行的删减):
接着我们输入:
该命令将启动core-platform Bundle(stop和start是常用的重启Bundle的命令),在Console中会显示如下提示信息(由于篇幅关系,这里的提示信息进行的删减):
从中我们可以看到,system.properties被重新加载了。
接着我们重启biz-share Bundle,和之前重启core-platform Bundle一样的方法,输入如下两个命令:
Console中会显示如下信息:
(图十)
我们在不停止OSGi容器的情况下,修改了全局配置参数,并让其他Bundle可以读取到修改之后的配置参数,这展现了OSGi在动态性方面的特性。在实际运行中,我们只需要重启core-platform Bundle就可以了,这里是为了演示修改前和修改后的参数值差异,所以重启了biz-share Bundle。
下一章中,我们将介绍开发框架提供的一些OSGi Annotations,它们可以帮助我们提高注册OSGi服务和使用OSGi的效率。
(图一)
在开发框架运行时容器启动的时候会自动的加载指定目录下的system.properties文件,该文件就是默认的全局参数配置文件,比如上例中的D:\home\admin\share\data\helloworld\system.properties。在assembly目录下提供了一个system.properties文件的默认模板,请在第一次启动开发框架时复制该文件到指定的目录,比如上例中的D:\home\admin\share\data\helloworld目录,否则就会看到如上一篇文章中所介绍的异常信息。下图展示了system.properties文件提供的默认配置内容:
(图二)system.properties内容
该文件中定义了一些默认的全局参数,比如:应用程序的工作目录路径,服务器的ID标识,数据库驱动配置等(开发框架支持MySQL的Master/Slave模式的配置,从上图中就可以看到,我们配置了2个数据库的URL参数,后续文章将对数据库相关操作进行详细的讨论)。当然你也可以添加自定义的参数,只要符合Java属性文件的格式即可。接下去让我们来看看全局配置参数加载器是如何工作的。请在Eclipse IDE中打开core-platform Bundle的bundle-context-osgi.xml文件,如下图所示:
(图三)
开发框架提供了一个OSGi的服务定义,org.storevm.eosgi.properties.loader.SystemPropertiesLoader,该服务用于在Bundle启动时加载system.properties属性文件。另外该服务还有一个“location”属性,用于定义system.properties文件的路径(如果路径中不提供文件名,则使用默认的system.properties做为文件名)。现在我们的全局参数已经全部被加载了,接下去我们将在程序中读取这些全局参数。
请打开biz-share Bundle中的bundle-context-osgi.xml配置文件,如下图所示:
(图四)
在该文件中开发框架提供了全局配置参数加载器服务的引入配置,如下代码:
<osgi:reference id="propertiesLoader" interface="org.storevm.eosgi.properties.loader.PropertiesLoader"/>
该配置将core-platform Bundle中发布的OSGi服务引入到biz-share Bundle中,这样在biz-share Bundle中就可以使用这个OSGi服务了,请看bundle-context.xml配置文件中的代码,如下:
<!-- OSGi service annotation processor --> <bean class="org.storevm.eosgi.core.annotation.OsgiServiceBeanPostProcessor" /> <bean class="org.storevm.eosgi.core.annotation.ServiceReferenceInjectionBeanPostProcessor" /> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" depends-on="propertiesLoader"/>
前2个配置是关于OSGi的annotation配置,下一章我们将对此进行详细讨论,这里我们暂时忽略它。第三个bean配置是我们经常用到的Spring的占位符替换的Bean。它依赖于我们的全局配置参数加载器服务的Bean。只有当PropertiesLoader服务实例化之后PropertyPlaceholderConfigurer才会进行实例化,这样,我们就可以在Spring XML中使用如下的配置了:
<bean id="masterDataSource" class="com.atomikos.jdbc.nonxa.AtomikosNonXADataSourceBean"> <property name="uniqueResourceName" value="${unique.resource.name.one}" /> <property name="url" value="${jdbc.url.one}" /> <property name="driverClassName" value="${jdbc.driverClassName}" /> <property name="user" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <property name="poolSize" value="20" /> <property name="borrowConnectionTimeout" value="60" /> <property name="testQuery" value="select 1" /> </bean>
其中用${}表示的占位符就是配置在system.properties文件中的属性值。
这里可能会有人提出疑问,PropertyPlaceholderConfigurer不是也提供了一个locations属性值用于指定属性配置文件的路径吗?是的,但是这里存在一个问题,PropertyPlaceholderConfigurer只能读取本Bundle中的*.properties文件,如果其他Bundle要读取相同的参数值,则需要在其他Bundle中重新再定义一个相同的*.properties文件,这是由OSGi的Classloader隔离机制所导致的,而且属性文件被打包到Bundle中,我们就失去了在运行时修改配置参数的灵活性,所以开发框架提供了一个单独的OSGi服务用于加载全局的配置参数,这样所有的Bundle只要引入该OSGi服务就能读取统一的配置参数了。以下代码展示了如何在代码中使用PropertiesLoader服务:
/** * * @author Administrator * @version $Id: SystemPropertiesLoaderTest.java, v 0.1 2013-2-26 下午6:33:40 Administrator Exp $ */ @Component public class SystemPropertiesLoaderTest { private static final Logger LOGGER = Logger.getLogger(SystemPropertiesLoaderTest.class); /* 全局参数加载器 */ private PropertiesLoader propertiesLoader; /** * 读取全局配置参数 */ @PostConstruct public void readProperties() { LogUtils.info(LOGGER, "读取全局配置参数, share.data.path={0}", propertiesLoader.getProperty("share.data.path")); } /** * Setter method for property <tt>propertiesLoader</tt>. * * @param propertiesLoader value to be assigned to property propertiesLoader */ public void setPropertiesLoader(PropertiesLoader propertiesLoader) { this.propertiesLoader = propertiesLoader; } }
从代码中我们可以看到,在readProperties方法中我们读取了“share.data.path”配置参数,从图二中我们可以看到share.data.path的参数值。由于我们使用了annotation,所以无需再在spring的配置文件中注册bean。在我们的开发框架中,所有bean的配置均使用annotation完成。好了,我们可以启动Eclipse中的OSGi运行时容器了,点击工具栏上的运行按钮,并选择“helloworld”,如下图所示:
(图五)
Console中会显示大量的启动日志信息,如果运行正常,你将会看到如下图所示的信息,表示我们的测试成功了:
(图六)
从上图可知,程序读取的“share.data.path”配置参数值和我们在system.properties文件中配置的值完全一样。目前我们使用的是开发框架提供的运行时环境来进行代码测试,后续文章我们将介绍开发框架提供的另外一种集成测试方法。
接下来我们将在OSGi容器的运行过程中,修改system.properties中的参数值,然后看看,在biz-share Bundel中是否读取到了修改之后的新值。
请在Console中输入“ss”命令,然后会列出所有的Bundle,如下图所示:
(图七)
我们查找core-platform和biz-share Bundle的id值,如下图所示(可能你的id与图中的不一样,以实际情况为准):
(图八)
从上图可以看到,biz-share Bundle的id是116,而core-platform Bundle的id是118。我们修改system.properties文件中的“share.data.path”配置项,如下图:
(图九)
我们在Console中的“osgi>”提示符下继续输入如下命令:
stop 118
该命令将停止core-platform Bunlde的运行,在Console中会显示如下提示信息(由于篇幅关系,这里的提示信息进行的删减):
osgi> stop 118 INFO [org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext] - Unpublishing application context OSGi service for bundle Helloworld... INFO [org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext] - Closing OsgiBundleXmlApplicationContext(bundle=helloworld-core-plat... INFO [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Destroying singletons in org.springframework.beans.factory.support... INFO [org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBean] - Unregistered service [ServiceRegistrationWrapper for {org.storevm... INFO [org.springframework.osgi.extender.internal.activator.ContextLoaderListener] - Application context succesfully closed (OsgiBundleXmlApplica...
接着我们输入:
start 118
该命令将启动core-platform Bundle(stop和start是常用的重启Bundle的命令),在Console中会显示如下提示信息(由于篇幅关系,这里的提示信息进行的删减):
INFO [org.springframework.osgi.extender.support.DefaultOsgiApplicationContextCreator] - Discovered configurations {osgibundle:/META-INF/spring/*.xml}... INFO [org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext] - Refreshing OsgiBundleXmlApplicationContext(bundle=helloworld-core-p... INFO [org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext] - Application Context service already unpublished osgi> INFO [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] - Loading XML bean definitions from URL [bundleentry://118.fwk18644877/META-... INFO [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] - Loading XML bean definitions from URL [bundleentry://118.fwk18644877/META-INF... INFO [org.springframework.osgi.extender.internal.dependencies.startup.DependencyWaiterApplicationContextExecutor] - No outstanding OSGi service ... INFO [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Pre-instantiating singletons in org.springframework.beans.factory.support... INFO [org.storevm.eosgi.properties.loader.PropertiesLoader] - 读取到全局配置文件路径, location=D:\home\admin\share\data\helloworld\system.properties INFO [org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBean] - Publishing service under classes [{org.storevm.eosgi.properties.loa... INFO [org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext] - Publishing application context as OSGi service with properties {org... INFO [org.springframework.osgi.extender.internal.activator.ContextLoaderListener] - Application context successfully refreshed (OsgiBundleXmlApplicatio...
从中我们可以看到,system.properties被重新加载了。
接着我们重启biz-share Bundle,和之前重启core-platform Bundle一样的方法,输入如下两个命令:
stop 116 start 116
Console中会显示如下信息:
(图十)
我们在不停止OSGi容器的情况下,修改了全局配置参数,并让其他Bundle可以读取到修改之后的配置参数,这展现了OSGi在动态性方面的特性。在实际运行中,我们只需要重启core-platform Bundle就可以了,这里是为了演示修改前和修改后的参数值差异,所以重启了biz-share Bundle。
下一章中,我们将介绍开发框架提供的一些OSGi Annotations,它们可以帮助我们提高注册OSGi服务和使用OSGi的效率。
相关文章推荐
- 基于OSGi的企业级开发框架实践——运行开发框架
- 基于OSGi的企业级开发框架实践——序篇
- 基于 OSGi的企业级开发框架实践——开发框架的创建
- 基于OSGi的企业级开发框架实践——发布和使用分布式OSGi服务
- 【基于OSGi的企业级开发框架实践——OSGi Annotations 】
- 基于OSGi的企业级开发框架实践——OSGi Annotations
- 基于 OSGi的企业级开发框架实践——认识OSGi和SpringDM
- JavaScript 项目构建工具 Grunt 实践:安装和创建项目框架
- 史上最简单 Robotium 跨进程操作实践——基于 ADB 框架
- 基于nodeJs express 框架的图片上传和编辑(引用美图编辑工具)上传小示例
- JavaScript 项目构建工具 Grunt 实践:安装和创建项目框架
- 【day 10】python编程:从入门到实践学习笔记- 基于Django框架的Web开发-Django入门(一)
- 基于C++的纯面向对象的通用高性能大并发TCP-SERVER/CLIENT开发框架实践系列之基础篇
- .NET领域驱动设计—初尝(一:疑问、模式、原则、工具、过程、框架、实践)
- 基于PCL的三维重建—贪婪投影三角化算法实践与参数设置
- 基于C++的纯面向对象的通用高性能大并发TCP-SERVER/CLIENT开发框架实践系列之前言篇
- 【day 14】python编程:从入门到实践学习笔记-基于Django框架的Web开发-用户账户(一)
- 基于python的接口测试框架设计(二)配置一些参数及文件
- 基于python3在nose测试框架的基础上添加测试数据驱动工具
- 史上最简单Robotium跨进程操作实践——基于ADB框架