Karaf教程第2部分 使用Configuration Admin服務
在Karaf教程的第1部分,我們學習瞭如何使用maven和blueprint提供和使用pojo服務,如何使用http服務釋出servlet。
在第2部分,我們集中精力關注OSGi bundle的配置。不像servlet容器,OSGi容器包含一個非常好的配置規範:來自企業級規範的Config Admin服務。在本教程中,我們將在純OSGi和blueprint中使用Config Admin服務,學習如何在bundle中自動部署配置檔案。
2.1 Configuration Admin服務規範
我們首先快速概覽一下Configuration Admin服務規範。對於我們來說,主要有兩個介面可以使用:
1、ConfigurationAdmin:允許獲取和改變配置。這個服務由Config Admin服務實現提供。
2、ManagedService:允許對配置改變產生影響。必須實現這個介面,並將它註冊給要被通知的服務。
所以,基本上在Config Admin服務中的配置是一個字典,這個字典包含了屬性和他們的值。字典由永續性標識PID標識。PID就是一個簡單的字串,它唯一標識了配置。
2.2 如何處理配置?
雖然你可以使用ConfigurationAdmin.getConfiguration介面獲取配置,但是我不推薦你這麼做。OSGi是動態的,所以有可能發生bundle在Config Admin服務之前啟動或者
所以,推薦的方式是使用ManagedService,並對更新做出反應。如果你的bundle沒有配置無法啟動,那麼在收到第一個更新時建立一個要被配置的pojo類是個好主意。
2.3 介紹要被配置的非常簡單的類
由於我們想要實現一個整潔風格的配置,那麼要被配置的類應該是純pojo。雖然可以簡單的實現ManagedService介面,直接使用Dictionary,但這將使你依賴於OSGi和當前的Config Admin規範。所以,替代做法是我們使用一個具有title熟悉的簡單的bean
public class MyApp {
String title;
public void setTitle(Stringtitle) {
this.title =title;
}
public void refresh() {
System.out.println("Configuration updated (title=" +title +")");
}
}
所以我們的目標就是當配置發生改變時,配置title,然後呼叫refresh方法。我們將在純OSGi和blueprint中做這件事。
2.4 練習一下:使用純OSGi介面處理配置
本教程的第1個練習演示如何只用OSGi介面使用Config Admin服務。雖然這可能不是你以後使用的方式,但這種方式可以幫助你理解更深層次的東西。
你可以在子目錄configapp中找到實現:(https://github.com/cschneider/Karaf-Tutorial/tree/master/configadmin/configapp)。
所以首先我們需要一個pom檔案用於maven構建。你最好從configapp示例程式的pom檔案開始。如果你新建了新的工程,你必須是使用maven-bundle-plugin外掛使你的工程成為一個bundle,你需要新增兩個依賴:
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.compendium</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<version>4.2.0</version>
</dependency>
第一個依賴用於獲取config admin服務介面,第二個依賴用於建立Activator,它包含基本的OSGi介面。
現在,我們關心如何更新MyApp類。下面這個類解決了這個問題。我們實現了ManagedService介面,來與Config Admin服務互動。所以無論什麼時候,配置發生改變,我們的方法都會被呼叫。第一件事是檢查是否為null,當config被移除時這是有可能發生的。這時我們可以停止MyApp,但為了簡單起見,我們只是忽略它。下一步是建立MyApp類。通常你可能會在Activator中例項化它,但是你不得不處理空配置,這是我們不希望的。最後是簡單地用從config中獲取的值呼叫setter方法,在所有的設定完成後再呼叫refresh方法。
private final class ConfigUpdaterimplements ManagedService {
@SuppressWarnings("rawtypes")
@Override
public void updated(Dictionaryconfig) throws ConfigurationException {
if (config ==null) {
return;
}
if (app ==null) {
app = new MyApp();
}
app.setTitle((String)config.get("title"));
app.refresh();
}
}
當然,這還是什麼事情都沒做。最後一步就是在Activator.start方法中註冊ConfigUpdater。我們簡單地使用registerService方法,就像每一個其他的服務一樣。唯一特殊的地方是你必須設定SERVICE_PID為config pid,這樣Config Admin服務就知道你想要監視的配置了。
Hashtable<String, Object> properties =new Hashtable<String, Object>();
properties.put(Constants.SERVICE_PID,CONFIG_PID);
serviceReg = context.registerService(ManagedService.class.getName(),new ConfigUpdater() ,properties);
2.5 執行這個簡單的示例
•用mvn install命令構建這個工程
•啟動一個全新的karaf例項
•將configapp.jar從target目錄複製到Karaf的deploy目錄
現在我們注意到似乎沒有發生任何事情。在Karaf控制檯呼叫list,你會看到這個bundle確實已經啟動了,但是它沒有任何輸出,因為它還沒有配置。我們仍然需要建立配置檔案,並設定title。
•複製已有的檔案/configadmin-features/src/main/resources/ConfigApp.cfg到Karaf的/etc目錄
這裡重要的部分是檔名必須是<pid>.cfg。這樣config admin服務才能找到它。
現在fileinstall bundle會在etc目錄檢測到新的檔案。由於檔案結尾是.cfg,它認為這是一個config admin資源,建立或更新由檔名確定的pid的Config Admin服務配置。
所以現在在Karaf控制檯你應該能看到下面的列印。這個列印顯示了配置改變被正確地檢測和轉發。如果你現在用編輯器改變了這個檔案並儲存,那麼這個變化也會被傳播。
2.6 使用Karaf config命令探究配置
在Karaf控制檯鍵入如下命令:
在其他的配置中,你應該找到上面的配置"ConfigApp"。這個配置顯示它從哪兒載入的,pid,當然還有在檔案中設定的所有屬性。
我們也可以改變這個配置:
我們看到這個修改直接傳播到了我們的bundle。如果你看看etc下面的配置檔案,你會發現這個改變已經持久化到了這個檔案。所以如果我們重啟了Karaf,修改還是生效的。
2.7 使用Blueprint配置
在純OSGi環境中處理了Config Admin服務之後,現在我們將看一看如何在Blueprint中實現同樣的功能。幸運地是,這是相當容易,就Blueprint為我們做的大多數的工作一樣。
我們僅僅定義了一個cm:property-placeholder元素。這個處理檔案的屬性佔位符的功能很相似,但是這裡是處理Config Admin服務。我們需要提供一個配置的PID和更新策略。更新策略我們選擇“reload”。這意味著在配置改變之後,blueprint上下文會被重新載入或反射改變。我們也設定了預設的屬性,當配置的PID找不到或者屬性不存在的時候,就會使用這些預設值。
整合我們的bean類通常是一個簡單的bean定義。在這個類中我們定義了title熟悉,分配一個佔位符,這個佔位符會使用config admin服務進行解析。唯一特別的是初始化方法。這個給了我們機會以便對配置改變之後做出反應,就像純OSGi示例中一樣。
對於bluenprint來說,我們不需要任何maven的依賴,因為我們的Java程式碼是純Java bean。只要將Blueprint上下文放在OSGI-INF/blueprint目錄中並且blueprint extender載入了,那麼blueprint上下文就被會簡單地啟用。由於As blueprint總是在Karaf中被載入,所以我們什麼都不需要做。
<?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://svn.apache.org/repos/asf/aries/trunk/blueprint/blueprint-cm/src/main/resources/org/apache/aries/blueprint/compendium/cm/blueprint-cm-1.1.0.xsd
">
<cm:property-placeholder persistent-id="ConfigApp" update-strategy="reload" >
<cm:default-properties>
<cm:property name="title" value="Default Title"/>
</cm:default-properties>
</cm:property-placeholder>
<bean id="myApp" class="net.lr.tutorial.configadmin.MyApp" init-method="refresh">
<property name="title" value="${title}"></property>
</bean>
</blueprint>
2.8 Deploying config files
在我們成功地使用了Config Admin服務之後,剩下要做的唯一一件事就是部署帶預設配置的bundle。這可以使用Karaf feature檔案實現。我們定義一個feature,帶有它需要的bundle,簡單地新增一個configfile元素。這使得Karaf部署給定的檔案到Karaf安裝位置的etc目錄。如果這個檔案已經存在,那麼它不會被覆蓋。
<feature name="tutorial-configadmin" version="${pom.version}">
<bundle>mvn:net.lr.tutorial.configadmin/configapp/${pom.version}</bundle>
<bundle>mvn:net.lr.tutorial.configadmin/configapp-blueprint/${pom.version}</bundle>
<configfile finalname="/etc/ConfigApp.cfg">mvn:net.lr.tutorial.configadmin/configadmin-features/${pom.version}/cfg</configfile>
</feature>
這樣,最後一個問題是如何將配置部署到maven,讓configfileonfig元素能夠找到它。這好像屬於Karaf中的the build-helper-maven-plugin的特性。請參見pom檔案瞭解使用細節。
2.9 Summing it up and a look into the future
在本教程中,我們學習瞭如何使用Config Admin服務以及如何在純OSGi和blueprint中使用該服務。我們也看到了如何構建和部署我們的工程。
雖然這已經很有用了,但在我看來,有一點點小問題。第一個問題是configfile似乎看起來與config admin不一致。實際上,Karaf不使用config admin服務部署檔案。所以我想要看到的是已經存在的config元素不僅僅是為了寫入配置,而且還用於持久化。幸運地是,我的同事Jean Baptiste正在研究這個問題。參見https://issues.apache.org/jira/browse/KARAF-888。
另一個問題是對於企業級環境,需要具有附加特性的config admin服務。一件是要可能在整個伺服器網路中進行配置,具有配置的中心源和友好的UI。另一件事是你不僅想要部署預設的配置,而且要部署管理員真正想要為系統進行的配置。所以,我想你能夠定義一個部署計劃,不僅要安裝bundle和feature,還需要配置的改變。如果這個正確的完成,將允許部署、配置改變的良好檢查,也允許管理員一旦在出錯的情況下回滾配置的變化。我希望我們可以在下一個Talend ESB EE釋出版中提供這樣的計劃。