熟悉基本知识 AEM项目原型使用,以及 FileVault Content Maven插件 因为本文是在这些学习和概念的基础上进行的。
本文概述了Adobe Experience Manager Maven项目要与AEMas a Cloud Service兼容,需要进行的更改,确保它们尊重可变和不可变内容的拆分。 此外,建立依赖关系以创建无冲突的确定性部署,并将它们打包到可部署的结构中。
AEM应用程序部署必须由单个AEM包组成。 此包继而应包含子包,子包中包含应用程序运行所需的一切,包括代码、配置和任何支持的基线内容。
AEM需要分离 内容 和 代码,这意味着单个内容包 无法 部署到 两者 /apps
和运行时可写区域(例如, /content
, /conf
, /home
,或任何其他内容 /apps
)。 相反,应用程序必须将代码和内容分离到离散包中,以部署到 AEM 中。
本文档中概述的包结构与本地开发部署和 AEM 云服务部署兼容。
本文档中概述的配置由 AEM项目Maven Archetype 24或更高版本.
此 /apps
和 /libs
考虑AEM的领域 不可变 因为它们在AEM启动(即在运行时)后无法更改(创建、更新、删除)。 在运行时更改不可变区域的任何尝试都将失败。
存放库中的所有其他内容, /content
, /conf
, /var
, /etc
, /oak:index
, /system
, /tmp
,等等,都是 可变 区域,这意味着它们可以在运行时更改。
与AEM的早期版本一样, /libs
不应修改。 只有AEM产品代码可以部署到 /libs
.
Oak索引(/oak:index
)由AEMas a Cloud Service部署过程管理。 这是因为Cloud Manager必须等到部署任何新索引并完全重新索引后,才能切换到新代码映像。
因此,尽管Oak索引在运行时是可变的,但必须将其部署为代码,以便在安装任何可变包之前可以安装它们。 因此 /oak:index
配置是代码包的一部分,而不是内容包的一部分 如下所述.
有关AEMas a Cloud Service索引的更多详细信息,请参阅 内容搜索与索引.
此图概述了推荐的项目结构和包部署对象。
推荐的应用程序部署结构如下:
将生成OSGi捆绑包Jar文件,并直接嵌入到所有项目中。
此 ui.apps
包中包含要部署的所有代码,并且仅部署到 /apps
. 的常见元素 ui.apps
包包括但不限于:
必须向所有环境部署相同的代码。 此代码可确保将暂存环境中的验证也投放到生产环境中。 有关更多信息,请参阅以下部分: 运行模式.
ui.content
包包含所有内容和配置。 内容包包含 ui.apps
或 ui.config
包,或者换言之,任何不在 /apps
或 /oak:index
. 的常见元素 ui.content
包包括但不限于:
/conf
/content
, /content/dam
, 依此类推./content/cq:tags
/etc
此 all
包是一个容器包,仅包含可部署构件、OSGI包Jar文件、 ui.apps
, ui.config
、和 ui.content
包作为嵌入。 此 all
包不得具有 任何内容或代码 ,而是将所有部署委派给存储库的子包或OSGi捆绑包Jar文件。
现在使用Maven包含包 FileVault Package Maven插件的嵌入式配置,而不是 <subPackages>
配置。
对于复杂的Experience Manager部署,可能需要创建多个 ui.apps
, ui.config
、和 ui.content
表示AEM中特定站点或租户的项目/包。 如果完成了此方法,请确保遵循可变和不可变内容之间的拆分,并将所需的内容包和OSGi捆绑Jar文件作为子包嵌入到中 all
容器内容包。
例如,复杂的部署内容包结构可能如下所示:
all
内容包嵌入以下包,以创建单个部署构件
common.ui.apps
部署所需的代码 两者 站点A和站点Bsite-a.core
站点A所需的OSGi包Jarsite-a.ui.apps
部署站点A所需的代码site-a.ui.config
部署站点A所需的OSGi配置site-a.ui.content
部署站点A所需的内容和配置site-b.core
站点B所需的OSGi包Jarsite-b.ui.apps
部署站点B所需的代码site-b.ui.config
部署站点B所需的OSGi配置site-b.ui.content
部署站点B所需的内容和配置此 ui.config
包包含所有 OSGi配置:
/apps/my-app/osgiconfig
/apps/my-app/osgiconfig/config
/apps/my-app/osgiconfig/config.<author|publish>.<dev|stage|prod>
config.<runmode>
文件夹(如上所述),并用于定义:
如果AEM部署使用其他AEM项目(这些项目本身由它们自己的代码和内容包组成),则其容器包应嵌入到项目的 all
包。
例如,包含两个供应商AEM应用程序的AEM项目可能如下所示:
all
内容包嵌入以下包,以创建单个部署构件
core
AEM应用程序所需的OSGi包Jarui.apps
部署AEM应用程序所需的代码ui.config
部署AEM应用程序所需的OSGi配置ui.content
部署AEM应用程序所需的内容和配置vendor-x.all
部署供应商X应用程序所需的一切(代码和内容)vendor-y.all
部署供应商Y应用程序所需的一切(代码和内容)要用声明的包类型标记包。 包类型有助于阐明包的用途和部署。
packageType
到 container
. 容器包不得包含常规节点。 仅允许OSGi包、配置和子包。 AEMas a Cloud Service中的容器不允许使用 安装挂钩.packageType
到 application
.packageType
到 content
.有关详细信息,请参阅 Apache Jackrabbit FileVault — 包Maven插件文档, Apache Jackrabbit包类型,以及 FileVault Maven配置片段 下面的。
请参阅 POM XML片段 部分,了解完整的代码片段。
默认情况下,AdobeCloud Manager会收集由Maven内部版本生成的所有包。 但是,由于容器(all
)包是包含所有代码和内容包的单个部署对象,您必须确保 仅限 容器(all
)包已部署。 要确保这一点,Maven 内部版本生成的其他包必须使用 <properties><cloudManagerTarget>none</cloudManageTarget></properties>
的 FileVault Content Package Maven Plug-In 配置进行标记。
请参阅 POM XML片段 部分,了解完整的代码片段。
Repo Init提供定义JCR结构的说明或脚本,从文件夹树等常见节点结构到用户、服务用户、组和ACL定义。
Repo Init的主要优势在于,它们具有执行由其脚本定义的所有操作的隐式权限。 而且,此类脚本会在部署生命周期的早期调用,以确保在运行代码时存在所有必需的JCR结构。
虽然Repo Init脚本本身在 ui.config
“项目”作为脚本,可以也应该使用它们来定义以下可变结构:
Repo Init脚本存储为 scripts
条目 RepositoryInitializer
OSGi工厂配置。 因此,它们可以通过运行模式隐式定位,从而在AEM Author和AEM Publish Services的Repo Init脚本之间甚至环境之间(Dev、Stage和Prod)产生差异。
Repo Init OSGi配置最好写入 .config
OSGi配置格式 因为它们支持多行,这与使用的最佳实践不同 .cfg.json
定义OSGi配置.
在定义用户和组时,只有组被视为应用程序的一部分,并且是其功能的组成部分。 您仍然可以在运行时在AEM中定义“组织用户和组”。 例如,如果自定义工作流将工作分配给指定组,请在AEM应用程序中通过Repo Init定义该组。 但是,如果分组只是组织性的,例如“Wendy's Team”和“Sean's Team”,则最好在AEM中运行时定义和管理这些组。
Repo Init脚本 必须 在内联中定义 scripts
字段,或 references
配置不起作用。
有关Repo Init脚本的完整词汇表,请访问 Apache Sling Repo初始文档.
请参阅 Repo Init代码段 部分,了解完整的代码片段。
代码包需要配置FileVault Maven插件的配置以引用 <repositoryStructurePackage>
这会强制实现结构依赖关系的正确性(以确保一个代码包不会安装在另一个代码包上)。 您可以 为您的项目创建自己的存储库结构包.
仅必需 对于代码包,是指任何标有 <packageType>application</packageType>
.
要了解如何为您的应用程序创建存储库结构包,请参阅 开发存储库结构包.
内容包(<packageType>content</packageType>
) 不要 需要此存储库结构包。
请参阅 POM XML片段 部分,了解完整的代码片段。
内容或代码包放置在特殊的“side-car”文件夹中,并可定向为在AEM author和/或AEM publish上安装,使用FileVault Maven插件的 <embeddeds>
配置。 请勿使用 <subPackages>
配置。
常见用例包括:
要定位AEM创作、AEM发布或两者,包将嵌入到 all
容器包位于特殊的文件夹位置,格式如下:
/apps/<app-name>-packages/(content|application|container)/install(.author|.publish)?
划分此文件夹结构:
第一级文件夹 必须是 /apps
.
第二级文件夹表示应用程序,其中 -packages
已发布到文件夹名称。 通常,所有子包都嵌入在仅有一个第二级文件夹下,但可以创建任意数量的第二级文件夹以最好地表示应用程序的逻辑结构:
/apps/my-app-packages
/apps/my-other-app-packages
/apps/vendor-packages
按照惯例,子包嵌入文件夹的名称带有后缀 -packages
. 此命名可确保部署代码和内容包能够 非 已部署任何子包的目标文件夹 /apps/<app-name>/...
导致破坏性的循环安装行为。
第三级文件夹必须是
application
, content
或 container
第4级文件夹包含子包,并且必须是以下项之一:
install
因此您安装 两者 AEM创作和AEM发布install.author
因此您安装 仅限 在AEM作者上install.publish
因此您安装 仅限 仅在AEM上发布 install.author
和 install.publish
是受支持的目标。 不支持其 他运行模式 。例如,包含AEM创作和发布特定包的部署可能如下所示:
all
容器包嵌入以下包,以创建单个部署构件
ui.apps
内嵌于 /apps/my-app-packages/application/install
将代码部署到AEM创作和AEM发布ui.apps.author
内嵌于 /apps/my-app-packages/application/install.author
将代码仅部署到AEM作者ui.content
内嵌于 /apps/my-app-packages/content/install
将内容和配置部署到AEM创作和AEM发布ui.content.publish
内嵌于 /apps/my-app-packages/content/install.publish
仅将内容和配置部署到AEM发布请参阅 POM XML片段 部分,了解完整的代码片段。
由于代码和内容子包嵌入到了容器包中,因此必须将嵌入的目标路径添加到容器项目的 filter.xml
. 这样做可以确保在构建容器包时将嵌入的包包含在容器包中。
只需添加 <filter root="/apps/<my-app>-packages"/>
包含要部署的子包的任意第二级文件夹的条目。
请参阅 POM XML片段 部分,了解完整的代码片段。
所有软件包必须可通过 Adobe的公共Maven工件存储库 或可访问的公共、可引用的第三方Maven对象存储库。
如果第三方包位于 Adobe的公共Maven工件存储库,AdobeCloud Manager无需进一步配置即可解析工件。
如果第三方包位于 公共第三方Maven工件存储库,此存储库必须在项目的 pom.xml
并嵌入到方法之后 上面概述.
第三方应用程序/连接器应使用其 all
在您的项目容器中打包为容器(all
)包。
添加Maven依赖项遵循标准Maven实践,嵌入第三方工件(代码和内容包)包括 上面概述.
请参阅 POM XML片段 部分,了解完整的代码片段。
ui.apps
起始日期 ui.content
包为确保正确安装包,建议建立包间依赖关系。
一般规则是包含可变内容的包(ui.content
)应依赖于不可变代码(ui.apps
),支持呈现和使用可变内容。
此常规规则的一个显着例外是如果不可变代码包(ui.apps
或任何其他), 仅限 包含OSGi包。 如果是,则任何AEM包都不应声明依赖该包。 原因在于,不可变的代码包能够 仅限 包含OSGi包,未向AEM注册 包管理器. 因此,任何依赖它的AEM包都存在未满足的依赖关系,无法安装。
请参阅 POM XML片段 部分,了解完整的代码片段。
内容包依赖项的常见模式包括:
简单的大小写设置 ui.content
可变内容包,依赖于 ui.apps
不可变代码包。
all
没有依赖关系
ui.apps
没有依赖关系ui.content
取决于 ui.apps
复杂部署会根据简单案例进行展开,并设置相应可变内容和不可变代码包之间的依赖关系。 根据需要,还可以在不可变代码包之间建立依赖关系。
all
没有依赖关系
common.ui.apps.common
没有依赖关系site-a.ui.apps
取决于 common.ui.apps
site-a.ui.content
取决于 site-a.ui.apps
site-b.ui.apps
取决于 common.ui.apps
site-b.ui.content
取决于 site-b.ui.apps
本文概述的项目结构和组织是 完全兼容 本地开发AEM实例。
以下是Maven pom.xml
可添加到Maven项目以与上述建议一致的配置片段。
作为子包部署的代码和内容包必须声明的包类型为 应用程序 或 内容,具体取决于它们包含的内容。
容器 all/pom.xml
项目 不会 声明 <packageType>
.
代码包必须设置其 packageType
到 application
.
在 ui.apps/pom.xml
,则 <packageType>application</packageType>
构建配置指令 filevault-package-maven-plugin
插件声明声明其包类型。
...
<build>
<plugins>
<plugin>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>filevault-package-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<group>${project.groupId}</group>
<name>my-app.ui.apps</name>
<packageType>application</packageType>
<accessControlHandling>merge</accessControlHandling>
<properties>
<cloudManagerTarget>none</cloudManagerTarget>
</properties>
</configuration>
</plugin>
...
内容包必须设置其 packageType
到 content
.
在 ui.content/pom.xml
,则 <packageType>content</packageType>
的构建配置指令 filevault-package-maven-plugin
插件声明声明其包类型。
...
<build>
<plugins>
<plugin>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>filevault-package-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<group>${project.groupId}</group>
<name>my-app.ui.content</name>
<packageType>content</packageType>
<accessControlHandling>merge</accessControlHandling>
<properties>
<cloudManagerTarget>none</cloudManagerTarget>
</properties>
</configuration>
</plugin>
...
在生成包的每个项目中,除容器 (all
) 项目外,将 <cloudManagerTarget>none</cloudManagerTarget>
添加到 filevault-package-maven-plugin
插件声明的 <properties>
配置中,以确保 Adobe Cloud Manager 不部署这些它们。容器(all
)包应当是通过Cloud Manager部署的单一包,它进而嵌入所有必需的代码和内容包。
...
<build>
<plugins>
<plugin>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>filevault-package-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
...
<properties>
<cloudManagerTarget>none</cloudManagerTarget>
</properties>
</configuration>
</plugin>
...
包含Repo初始脚本的Repo初始脚本在 RepositoryInitializer
OSGi工厂配置,通过 scripts
属性。 由于这些脚本是在OSGi配置中定义的,因此可以使用常规运行模式轻松限定其作用域 ../config.<runmode>
文件夹语义。
由于脚本通常是多行声明,因此更易于在中定义它们 .config
文件,而不是基于JSON的 .cfg.json
格式。
/apps/my-app/config.author/org.apache.sling.jcr.repoinit.RepositoryInitializer-author.config
scripts=["
create service user my-data-reader-service
set ACL on /var/my-data
allow jcr:read for my-data-reader-service
end
create path (sling:Folder) /conf/my-app/settings
"]
此 scripts
OSGi属性包含由定义的指令 Apache Sling的Repo初始语言.
在 ui.apps/pom.xml
和任何其他 pom.xml
声明代码包(<packageType>application</packageType>
),将以下存储库结构包配置添加到FileVault Maven插件。 您可以 为您的项目创建自己的存储库结构包.
...
<build>
<plugins>
<plugin>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>filevault-package-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
...
<repositoryStructurePackages>
<repositoryStructurePackage>
<groupId>${project.groupId}</groupId>
<artifactId>ui.apps.structure</artifactId>
<version>${project.version}</version>
</repositoryStructurePackage>
</repositoryStructurePackages>
</configuration>
</plugin>
...
在 all/pom.xml
,添加以下内容 <embeddeds>
指令 filevault-package-maven-plugin
插件声明。 记住, 不要 使用 <subPackages>
配置。 原因是它包括中的子包 /etc/packages
而不是 /apps/my-app-packages/<application|content|container>/install(.author|.publish)?
.
...
<plugin>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>filevault-package-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
...
<embeddeds>
<!-- Include the application's ui.apps and ui.content packages -->
<!-- Ensure the artifactIds are correct -->
<!-- OSGi Bundle Jar file that deploys to BOTH AEM Author and AEM Publish -->
<embedded>
<groupId>${project.groupId}</groupId>
<artifactId>my-app.core</artifactId>
<type>jar</type>
<target>/apps/my-app-packages/application/install</target>
</embedded>
<!-- Code package that deploys to BOTH AEM Author and AEM Publish -->
<embedded>
<groupId>${project.groupId}</groupId>
<artifactId>my-app.ui.apps</artifactId>
<type>zip</type>
<target>/apps/my-app-packages/application/install</target>
</embedded>
<!-- OSGi configuration code package that deploys to BOTH AEM Author and AEM Publish -->
<embedded>
<groupId>${project.groupId}</groupId>
<artifactId>my-app.ui.config</artifactId>
<type>zip</type>
<target>/apps/my-app-packages/application/install</target>
</embedded>
<!-- Code package that deploys ONLY to AEM Author -->
<embedded>
<groupId>${project.groupId}</groupId>
<artifactId>my-app.ui.apps.author</artifactId>
<type>zip</type>
<target>/apps/my-app-packages/application/install.author</target>
</embedded>
<!-- Content package that deploys to BOTH AEM Author and AEM Publish -->
<embedded>
<groupId>${project.groupId}</groupId>
<artifactId>my-app.ui.content</artifactId>
<type>zip</type>
<target>/apps/my-app-packages/content/install</target>
</embedded>
<!-- Content package that deploys ONLY to AEM Publish -->
<embedded>
<groupId>${project.groupId}</groupId>
<artifactId>my-app.ui.content.publish-only</artifactId>
<type>zip</type>
<target>/apps/my-app-packages/content/install.publish</target>
</embedded>
<!-- Include any other extra packages -->
<embedded>
<groupId>com.vendor.x</groupId>
<artifactId>vendor.plug-in.all</artifactId>
<type>zip</type>
<target>/apps/vendor-packages/container/install</target>
</embedded>
<embeddeds>
</configuration>
</plugin>
...
在 all
项目的 filter.xml
(all/src/main/content/jcr_root/META-INF/vault/definition/filter.xml
), include 任意 -packages
包含要部署的子包的文件夹:
<filter root="/apps/my-app-packages"/>
如果多个 /apps/*-packages
在嵌入目标中使用,则必须在此处枚举所有对象。
添加更多Maven存储库可能会延长Maven构建时间,因为会检查其他Maven存储库的依赖关系。
在反应栈项目的 pom.xml
,添加任何必要的第三方公共Maven存储库指令。 完整 <repository>
配置应该可以从第三方存储库提供商获得。
<repositories>
...
<repository>
<id>3rd-party-repository</id>
<name>Public Third-Party Repository</name>
<url>https://repo.3rdparty.example.com/...</url>
<releases>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
...
</repositories>
ui.apps
起始日期 ui.content
包在 ui.content/pom.xml
,添加以下内容 <dependencies>
指令 filevault-package-maven-plugin
插件声明。
...
<plugin>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>filevault-package-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
...
<dependencies>
<!-- Declare the content package dependency in the ui.content/pom.xml on the ui.apps project -->
<dependency>
<groupId${project.groupId}</groupId>
<artifactId>my-app.ui.apps</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
...
</configuration>
</plugin>
...
在 all/pom.xml
,添加 maven-clean-plugin
此插件用于在Maven构建之前清理目标目录。
<plugins>
...
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<executions>
<execution>
<id>auto-clean</id>
<!-- Run at the beginning of the build rather than the default, which is after the build is done -->
<phase>initialize</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
...
</plugins>