現在來試試怎樣用DS實作動态配置一個Web應用程式界面裡菜單,使用的OSGi實作還是Equinox。Eclipse裡菜單項是通過實作actionSets、editorActions等等擴充點添加的,在OSGi裡沒有這些“擴充點”,沒關系,我們可以自己定義。
一、用一個Bundle定義Java接口檔案,和Eclipse擴充點的功能類似,這些接口可以作為服務的接入點。例子裡這個Bundle的ID是net.bjzhanghao.osgi.services,接口類是IMenuContributor,内容很簡單如下所示:
public interface IMenuContributor {
public List<MenuItem> getItems();
}
上面用到的MenuItem是自己定義的一個簡單的資料結構,包含name和url兩個String類型的成員變量和相應的getter/setter方法,這裡就不展示了。
二、用0..n個Bundle實作上面定義的接口(暫時稱之為Contributor),并聲明為服務。例子裡有兩個這樣的Bundle,ID分别是net.bjzhanghao.osgi.menu.contributor和net.bjzhanghao.osgi.menu.contributor2,實作類都是MyMenuContributor,前者提供了Menu1..3,後者提供了Menu4..5;以下是服務的聲明,即項目裡OSGI-INF/component.xml檔案的内容:
<?xml version="1.0" encoding="UTF-8"?>
<component name="services">
<implementation
class="net.bjzhanghao.osgi.menu.contributor.MyMenuContributor"/>
<service>
<provide interface="net.bjzhanghao.osgi.services.IMenuContributor"/>
</service>
</component>
MyMenuContributor實作IMenuContributor,你可以任意實作它,例子裡是讓它提供三個菜單項:
public class MyMenuContributor implements IMenuContributor {
public List<MenuItem> getItems() {
List<MenuItem> list = new ArrayList<MenuItem>();
list.add(new MenuItem("Menu1", null));
list.add(new MenuItem("Menu2", null));
list.add(new MenuItem("Menu3", null));
return list;
}
三、現在SOA的一半工作也就是注冊服務的部分完成了,剩下要做的是另一半,消費這些服務。首先在web應用程式Bundle裡,建立一個Helper類收集這些服務,這個Helper類的功能相當于一個Registry。例子裡這個Bundle的ID是net.bjzhanghao.osgi.example,Helper類是MenuHelper;以下是對MenuHelper的配置,即項目裡OSGI-INF/component.xml檔案的内容,這樣OSGi在啟動Bundle時會把實作IMenuContributor的服務通過addMenuContributor方法注冊到MenuHelper裡,注意cardinality的值要為"0..n",policy的值要為"dynamic":
<component name="menuHelper">
<implementation
class="net.bjzhanghao.osgi.example.MenuHelper"/>
<reference name="menuHelper"
interface="net.bjzhanghao.osgi.services.IMenuContributor"
cardinality="0..n"
policy="dynamic"
bind="addMenuContributor"
unbind="removeMenuContributor"
/>
四、在JSP/Servlet裡,利用上面的Helper類構造界面(或業務邏輯)。因為我們定義的接口是關于菜單的,是以例子應用的菜單會根據Bundle配置(啟動/停止)變化。例子裡是在ExampleServlet裡實作的,代碼很簡單如下所示:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
resp.getWriter().write("Hello<br/>");
resp.getWriter().write("<ul>");
for (IMenuContributor menuContributor : MenuHelper.getInstance().getMenuContributors()) {
for (MenuItem mItem : menuContributor.getItems()) {
resp.getWriter().write("<li><a href=\"" + mItem.getUrl() + "\">" + mItem.getName() + "</a></li>");
}
resp.getWriter().write("</ul>");
五、執行方式:
1、在Eclipse裡導入代碼包裡所有項目,啟動上述所有項目及其依賴的項目(Add Required Bundles),見下圖:
2、在浏覽器裡輸入位址http://localhost/exampleServlet,應該可以看到五個菜單項,見下圖(這個簡單的例子裡沒有考慮順序問題,是以Menu4..5可能出現在前面,使用類似Eclipse裡為Menu預留位置的方式可以解決):
3、回到Eclipse,在Console裡輸入ss檢視目前的Bundle,應該可以看到類似下圖的内容:
4、在Console裡輸入stop 35(35是Contributor的Bundle序号),Console會提示“Calling removeMenuContributor”,然後到浏覽器裡重新整理頁面,應該看到菜單項隻剩下Menu4..5。
<a href="http://files.cnblogs.com/bjzhanghao/net.bjzhanghao.osgi.example2.zip">代碼下載下傳</a>