天天看點

來自 Adobe 的使用者體驗專家 AEM 之:建構并部署 OSGi bundle

CQ 的建構基于

​​OSGi​​ 容器,是以自定義的代碼和功能能夠通過 OSGi 提供的 feature 添加到 CQ。要将自定義的代碼部署到 OSGi 容器,開發者必須将他們的代碼作為一個 bundle 進行打包。一個 OSGi bundle 隻是一個添加了額外中繼資料的 jar 檔案。本文将詳細介紹如何使用 Apache Maven 來建立一個 OSGi bundle,以及如何将該 bundle 部署到一個正在運作的 CQ 執行個體中去。

建構一個 OSGi bundle

對于一名 CQ 開發者來說要建構一個 OSGi bundle 最簡單的辦法就是通過

​​Apache Felix Bundle 插件​​使用 Apache Maven。這一插件由 Apache Felix 團隊基于 Peter Kriens 的

​​BND​​ 工具所開發,盡管如此,它所建立的 OSGi bundle 并不隻是針對于 Felix,它同樣可以為其它 OSGi 容器所用。

這個插件允許開發者處理起來就像使用 Maven (通過指令行或者一個 IDE 工具)建立一個基本的 jar 檔案那樣,但卻可以提供對添加到 bundle 中的 OSGi 中繼資料進行低級别的控制。

第一步是建立一個新的 Maven 項目,将打包樣式設定為 bundle,當然還有添加 Apache Felix Bundle 插件的定義。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
       <groupId>com.headwire.cqblueprints</groupId>
       <artifactId>parent</artifactId>
       <version>5.4.0-SNAPSHOT</version>
   </parent>
   <artifactId>cqblueprints-examples-osgi-bundle</artifactId>
   <packaging>bundle</packaging>
    ...
   <build>
       <pluginManagement>
           <plugins>
               <plugin>
                   <groupId>org.apache.felix</groupId>
                   <artifactId>maven-bundle-plugin</artifactId>
                   <version>2.3.5</version>
                   <extensions>true</extensions>
               </plugin>
                ...
           </plugins>
       </pluginManagement>
       <plugins>
           <plugin>
               <groupId>org.apache.felix</groupId>
               <artifactId>maven-bundle-plugin</artifactId>
                ...
           </plugin>
       </plugins>
   </build>
    ...
</project>      

下一步是對 Apache Felix Bundle 插件進行配置:

<plugin>
               <groupId>org.apache.felix</groupId>
               <artifactId>maven-bundle-plugin</artifactId>
               <configuration>
                   <instructions>
                       <Bundle-Activator>com.headwire.cqblueprints.examples.osgi.Activator</Bundle-Activator>
                       <Private-Package>com.headwire.cqblueprints.examples.osgi</Private-Package>
                       <Embed-Dependency>*;scope=compile|runtime</Embed-Dependency>
                       <Embed-Directory>OSGI-INF/lib</Embed-Directory>
                       <Embed-Transitive>true</Embed-Transitive>
                       <Import-Package>!org.slf4j.impl,*</Import-Package>
                   </instructions>
               </configuration>
           </plugin>      

以上例子設定了以下幾個配置項:

<Bundle-Activator>

OSGi Bundle Activator (綁定到 OSGi bundle 生命周期的一個類,通過它我們可以在諸如 bundle 啟動或者關閉的時候執行自定義的代碼)的完整的 Java 類名。這一設定是可選的。

<Private-Package>

不應該暴露給 OSGi 容器的包(比如隻包含有實作類而非 bundle 所提供 API 相關功能的一些包)。上面的例子将 Activator 所在的包聲明為 private。

<Embed-Dependency>

在建立 bundle 時要嵌入哪些 Maven 依賴。上述例子中設定為

*;scope=compile|runtime 是因為将要包含 scope 為 compile 或 runtime 的所有依賴,這些将成為 bundle 正常運作所需要的所有的類。

建議在你的 bundle 裡加入這個依賴項配置。替代方法就是不必在 bundle 裡嵌入依賴項,而是從 OSGi 容器中導入依賴項。

我們推薦前者,因為它使其他開發人員能夠更輕松地使用 bundle,而不必去追溯所有的依賴并在部署新 bundle 時将他們先部署進來。

任何在 bundle 編譯時需要而在運作時由 OSGi 容器所提供的依賴(舉個例子,

org.osgi.framework 包裡的所有的類)應該進行 scope 為 provided 的聲明 - 這樣它們就不會被嵌入進 bundle 裡去了。

<Embed-Directory>

嵌入的第三方包将會放在該 bundle 中的位置。将其設定為

OSGI-INF/lib。OSGI-INF 目錄是 OSGi 相關的其它中繼資料将要放置的地方,這個也模仿自大多數 Java 開發者所熟悉的

WEB-INF/lib 目錄。

<Embed-Transitive>

是否隻嵌入該 bundle pom 的直接依賴(要嵌入的話将其設定為 false),或者是否還要嵌入 pom 所聲明的依賴關系的傳遞圖 (要嵌入的話将其設定為 true)。将此項設定為 true,因為這将會讓我們更加容易地去處理該 bundle。如果有一些不應該包含進來的依賴(比如可能有其它 bundle 将它們設定成了對整個項目都可見,結果就是 - 包沖突),可以使用 Embed-Dependency 标簽将它們給過濾掉。

<Import-Package>

該 bundle 所需要的由 OSGi 容器所提供的包(比如,bundle 自身需要的自己卻沒有嵌入的一些類)。由于使用預設值就足夠了,這個标簽通常會被忽略。最終值将不僅包含 bundle 代碼中所需要的包,而且還包括由已嵌入的任何依賴項所需要的包。如果該 bundle 導入的某個類沒有在 OSGi 容器中提供,該 bundle 仍然能夠被安裝,但卻無法被啟動。

bundle 的建立成功之後,所需要的OSGi 中繼資料将被添加到該 jar 的

MANFIFEST.MF 檔案,而且所有的依賴也會被嵌入到了

OSGI-INF/lib 目錄中。

更多關于這些以及其它選項的詳細資訊請參見

​​Apache Felix Bundle 插件頁面​​。

部署一個 OSGi bundle

建立 OSGi bundle 的 Maven POM 配置好以後,接下來還要為部署該 bundle 到一個運作中的 CQ 環境對其進行繼續配置。

由于 CQ 的建構基于

​​Apache Sling​​,我們可以使用該項目的一個 Maven 插件将 OSGi bundle 直接部署到 CQ。

​​Maven Sling 插件​​使我們能夠将一個 OSGi bundle 部署到一個本地或遠端運作中的 CQ 執行個體中去。

接下來,在該 POM 中添加一個新的 profile,在該 profile 中添加一個插件的定義以啟用 Maven Sling 插件。

<profiles>
  <profile>
    <id>auto-deploy</id>
    <build>
      <pluginManagement>
        <plugins>
          <plugin>
            <groupId>org.apache.sling</groupId>
            <artifactId>maven-sling-plugin</artifactId>
            <version>2.0.4-incubator</version>
          </plugin>
        </plugins>
      </pluginManagement>
      <plugins>
        <plugin>
          <groupId>org.apache.sling</groupId>
          <artifactId>maven-sling-plugin</artifactId>
          <executions>
            <execution>
              <id>deploy-to-cq</id>
              <phase>install</phase>
              <goals>
                <goal>install</goal>
              </goals>
              <configuration>
                <slingUrl>${crx.url}/system/console/install</slingUrl>
                <user>${crx.user}</user>
                <password>${crx.password}</password>
              </configuration>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </build>
  </profile>
</profiles>      

在一個 profile 裡聲明 Sling 插件并且對于該 profile 預設不激活,這很重要,這是因為如果不能連接配接到指定的 CQ 執行個體的話 Sing 插件将會導緻 Maven 建構失敗。通過将 Sling 插件丢到一個 profile 裡,Maven 将能夠建構并釋出 bundle,而無需有一個可用的正在運作的 CQ 執行個體。

盡管如此,在重部署環境下,隻需簡單激活這個

auto-deploy profile,然後每次在運作 Maven install 時 ,該 bundle 将會被自動重新部署到 CQ。指令行示例如下所示:

mvn -Pauto-deploy clean install

大多數常見的 IDE (Eclipse,NetBeans 等等) 都允許開發者在執行 Maven 建構的時候配置哪些 profile 是可用的。

通過 Maven properties 的使用将 Sling 的連接配接配置進行參數化也很重要,這樣建構就可以輕松地在多個開發者的機器上執行,但在 POM 中還是要提供預設值。

<properties>
  <crx.url>http://localhost:4502</crx.url>
  <crx.user>admin</crx.user>
  <crx.password>admin</crx.password>
</properties>      

當預設值不可用的時候,可以使用标準 Maven 功能對它們進行輕松重寫。對伺服器 URL 進行指令行一次性建構重寫的示例如下:

mvn -Pauto-deploy -Dcrx.url=http://localhost:8080 clean install

或者進行更永久化的重寫,将該 property 直接添加到使用者的 settings.xml 檔案:

<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
...
  <profiles>
  ...
    <profile>
      <id>local-crx-settings</id>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
      <properties>
        <crx.url>http://localhost</crx.url>
      </properties>
    </profile>
  </profiles>
</settings>      

Maven 建構執行之後,如果部署成功,該 bundle 将會被安裝并啟動。取決于該 bundle 所做的事情,任何負面影響應該可以立即看到。最後,該 bundle 将會在管理者控制台的 Bundles 螢幕中列出,預設位置是:

​​http://localhost:4502/system/console/bundles

​​

作者簡介