动态的OSGI配置

在OSGI语境下,很多元素都脱离不了动态的特征,配置也不例外。我们期望修改配置时可以在不重启OSGI Framework的情况下就能生效,OSGI为此提供了一个ConfigAdmin的机制。首先,看看demo8的代码,demo8里只有一个java类com.ponder.Demo.demo8.configurator,这个类实现了org.osgi.service.cm.ManagedService接口;org.osgi.service.cm.ManagedService接口里只有一个方法:public void updated(Dictionary dctnr);同时,我们在demo8里加了一个blueprint.xml,这个blueprint很简单,只是将configurator这个类实例化,并发布出一个OSGI服务,服务的接口就是org.osgi.service.cm.ManagedService。发布这个服务时,我们指定了一个服务属性:service.pid=com.ponder.Demo.demo8;我们将demo8编译后得到demo8-1.0.jar,将它部署到servicemix上,这时,我们可以通过ls命令看到demo8按我们的预期,发布了一个OSGI服务。我们再手工编辑一个文件:com.ponder.Demo.demo8.cfg

demo8package=com.ponder.Demo.demo8
demo8version=1.0
author=killko

这个文件很简单,就是每行一个“xxxx=xxxx”这样的形式编辑好后,将这个文件复制到/etc文件夹下,这时,我们就可以看到configurator里的updated方法被调用,将com.ponder.Demo.demo8.cfg里的配置数据输出来了。我们再次改动com.ponder.Demo.demo8.cfg里的内容,并保存,就可以看到updated方法再次被调用。很明显,com.ponder.Demo.demo8.cfg里的数据是通过updated的参数dictionary dctnr注入进去的。那么,servicemix是怎么实现这个的呢?在servicemix里,已经预先集成了一些实现ConfigAdmin的bundle,它们会“监听”到etc文件夹下文件的变化;当我们将com.ponder.Demo.demo8.cfg文件复制到etc文件夹下时,这些bundle就读取其中的内容,放入一个Dictionary对象里,然后,找到所有服务属性service.pid=com.ponder.Demo.demo8的ManagedService的OSGI服务,将这个Dictionary对象作为参数调用updated方法。这里,com.ponder.Demo.demo8.cfg的文件名中“com.ponder.Demo.demo8”这部分,就被作为寻找相应ManagedService服务的条件。在文件被改动时,同样的操作也被再次触发,于是,我们就可以在配置被改动时及时地更新运行中的应用里的配置信息。通过文件名和ManagedService的service.pid匹配的形式来决定配置该注入哪里,这个只是servicemix自身约定俗成的一个方式,ConfigAdmin机制的本质只是由一些专门的bundle根据ManagedService的服务属性service.pid的值来实现配置动态更新而已,不应拘泥于特定的形式。

利用blueprint来实现ConfigAdmin

上节通过实现ManagedService接口的方式来实现ConfigAdmin,这节,我们换一种方式,利用blueprint的方式来更方便地实现配置的管理。我们来看看demo9的代码:demo9里,我们定义了一个类SomeBean,里面有三个属性,以及相应的setter和getter。demo9的blueprint.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
           xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0 http://aries.apache.org/schemas/blueprint-cm/blueprint-cm-1.1.0.xsd">
    <cm:property-placeholder persistent-id="com.ponder.Demo.demo9" update-strategy="reload">
        <cm:default-properties>
            <cm:property name="package" value="com.ponder.Demo.demo9"/>
            <cm:property name="version" value="1.0"/>
            <cm:property name="author" value="killko"/>
        </cm:default-properties>
    </cm:property-placeholder>
    <bean id="somebean" class="com.ponder.Demo.demo9.SomeBean">
        <property name="demo9package" value="${package}"/>
        <property name="demo9version" value="${version}"/>
        <property name="author" value="${author}"/>
    </bean>
</blueprint>

demo9的blueprint里多了一个命名空间,xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"在这个命名空间里,提供了一个的标签,它定义了配置的占位符。我们在bean里用property指定了几个属性,分别对应了bean里的几个setter,值是通过${xxxx}这样的占位符形式指定的。在servicemix上部署demo9-1.0.jar,我们会得到预期的输出:

demo9package被注入,值为:com.ponder.Demo.demo9
demo9version被注入,值为:1.0
author被注入,值为:killko

我们可以尝试将配置文件com.ponder.Demo.demo9.cfg编辑好,放到etc文件夹下,可以看到配置值被重新注入。<cm:property-placeholder/>标签下的persistent-id指定了ConfigAdmin对应的service.pid。

登录发表评论 注册

反馈意见