在 wildfly jar 中包含第三方库(keycloak SPI)

Posted

技术标签:

【中文标题】在 wildfly jar 中包含第三方库(keycloak SPI)【英文标题】:Include third party library in wildfly jar (keycloak SPI) 【发布时间】:2021-04-01 08:00:17 【问题描述】:

我正在使用服务提供者接口为 keycloak 创建插件(提供者)。我已经能够建立一对。现在我需要添加 smallrye-graphql-client 库来查询 graphql 服务器。但是,当我部署插件时,在类路径中找不到该库。

问题

    是否仍然可以创建包含依赖库的 jar? 如果 1 不可能,可以通过战争来完成吗? 如何将库添加到类路径。最好将它们与插件一起添加,而不是静态添加到 Wildfly。我正在使用gradle。更多详情如下。

背景资料

我成功地为它创建了一个类和集成测试。但是,当我将插件部署到 keycloak 时,出现以下错误:

16:38:38,127 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (default task-1) 
             Uncaught server error: java.util.ServiceConfigurationError: no 
             io.smallrye.graphql.client.typesafe.api.GraphQlClientBuilder in classpath

我已将 gradle 配置为包含导致问题的依赖项并将其添加到类路径中。我怀疑我应该在 jboss-deployment-structure.xml 中添加一个条目,但我不知道我应该在那里写什么。

gradle 配置

plugins 
    id 'war'
    id 'java-library'
    id 'maven-publish'

repositories 
    mavenLocal()
    mavenCentral()
    jcenter()

configurations 
    dependenciesToInclude

dependencies 
    dependenciesToInclude "io.smallrye:smallrye-graphql-client:1.0.20"


    providedCompile group: 'javax.enterprise', name: 'cdi-api', version: '2.0'
    providedCompile "org.keycloak:keycloak-server-spi:$keycloakVersion"
    providedCompile "org.keycloak:keycloak-server-spi-private:$keycloakVersion"
    providedCompile("org.keycloak:keycloak-services:$keycloakVersion") 
        exclude group: 'org.slf4j', module: 'slf4j-api'
        exclude group: 'org.slf4j', module: 'slf4j-log4j12'
    
    providedCompile group: 'org.keycloak', name: 'keycloak-model-api', version: '1.8.1.Final'
    providedCompile "org.jboss.resteasy:resteasy-jaxrs"

    providedCompile group: 'org.eclipse.microprofile.graphql', name: 'microprofile-graphql-api', version: '1.0.3'
    compile group: 'org.apache.geronimo.config', name: 'geronimo-config-impl', version: '1.2.2'
    configurations.compile.extendsFrom(configurations.dependenciesToInclude)



jar 
    manifest 
        attributes(
                "Class-Path": configurations.dependenciesToInclude.collect  it.getName() .join(' '))
    
    from 
        configurations.dependenciesToInclude.collect  it.isDirectory() ? it : zipTree(it) 
    

❯ cat META-INF/MANIFEST.MF                                                                                                                                                                                                     ─╯
Manifest-Version: 1.0
Class-Path: smallrye-graphql-client-1.0.20.jar geronimo-config-impl-1.2.
 2.jar smallrye-graphql-client-api-1.0.20.jar microprofile-graphql-api-1
 .0.3.jar microprofile-config-api-1.3.jar org.osgi.annotation.versioning
 -1.0.0.jar

下面是 jboss-deployment-structure.xml。在那里你可以看到我尝试包含 graphql 库(已注释掉)

<jboss-deployment-structure>
    <deployment>
        <dependencies>
            <module name="org.keycloak.keycloak-services"/>
            <module name="org.keycloak.keycloak-saml-core-public"/>
            <module name="org.apache.commons.codec"/>
            <module name="org.apache.commons.lang"/>
            <module name="org.jboss.logging"/>
            <!--            <module name="io.smallrye.smallrye-graphql-client"/>-->
        </dependencies>
    </deployment>
</jboss-deployment-structure>

我正在使用 Keycloak 11.0.2 (WildFly Core 12.0.3.Final)

【问题讨论】:

【参考方案1】:

我不确定我是否正确理解了将库静态添加到 jboss 的内容。我会根据我对您的问题的理解来回答。 您的问题有多种解决方案。

Jboss 依赖项

您应该首先了解 JBoss 如何解析其类和依赖项。我将非常简单地解释。 JBoss 分为模块和部署。

模块放置在 JBoss 的主文件夹中。模块是您在运行时不会更改的库。 每个模块都有一个名为 module.xml 的描述符文件,您可以在其中定义工件、依赖项和模块的名称。 文件 module.xml 基本上类似于模块世界中的 jboss-deployment-structure.xml。

部署被放置在部署文件夹中,并且可以在 JBoss 服务器运行时重新部署。如果部署需要依赖另一个模块/部署,它需要包含在给定部署的 jboss-deployment-structure 中。 Note that modules cannot be dependent on deployments but it works the other way around

您可以在互联网上找到更多信息,但这是您可以使用的基本信息。

解决方案 1 - JBoss 模块

如果你想在 JBoss 中获取对模块的依赖,你需要在 module.xml 中找到它的名称并将其写入你的 jboss-deployment-structure.xml(假设你的库是一个部署)

例如,如果您想要依赖于 keycloak 模块路径中的 jackson-dataformat-cbor-2.10.5.jar:

modules/system/layers/keycloak/com/fasterxml/jackson/dataformat/jackson-dataformat-cbor/main/jackson-dataformat-cbor-2.10.5.jar

在同一个文件夹中有一个module.xml,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!--
  ~ Copyright 2019 Red Hat, Inc. and/or its affiliates
  ~ and other contributors as indicated by the @author tags.
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~ http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  -->
<module name="com.fasterxml.jackson.dataformat.jackson-dataformat-cbor" xmlns="urn:jboss:module:1.3">
    <resources>
        <resource-root path="jackson-dataformat-cbor-2.10.5.jar"/>
    </resources>

    <dependencies>
        <module name="com.fasterxml.jackson.core.jackson-core"/>
        <module name="com.fasterxml.jackson.core.jackson-databind"/>
        <module name="com.fasterxml.jackson.core.jackson-annotations"/>
    </dependencies>
</module>

这意味着您的模块名称是 com.fasterxml.jackson.dataformat.jackson-dataformat-cbor,这就是您在 jboss-deployment-structure.xml 中作为依赖项放入的名称。

你的情况

在您的情况下,您需要对 smallrye-graphql-client 的依赖关系,该依赖关系不包含在 JBoss 模块中。这意味着您必须在此处添加它。 通过在层中创建文件夹来创建 JBoss 层: modules/system/layers/[name of your layer] 这样做之后,您还应该在modules/layers.conf 中包含您的层。您可以通过在 keycloak 层之后写逗号来包含它,如下所示:

layers=keycloak,[your layer]

创建之后,您可以将插件添加到图层中,例如: modules/system/layers/[name of your layer]/org/my/plugins/main

文件夹内将是:

你的罐子 module.xml(根据其他模块创建)

那么你唯一要做的就是在你的 jboss-deployment-structure.xml 中包含这个模块作为依赖。 (您总是包含模块的名称)

Note that you might have to add more libraries as dependencies to your modules. You can include all of it in the modules

如果你不喜欢手动创建这些东西,你可以创建 jboss-modules-builder ,比如这个。它将使用 maven 创建您的模块 xml:

https://github.com/marcel-ouska/jboss-modules-builder

解决方案 2 - 胖 JAR/WAR

基本上,如果您想要一个简单的解决方案,您可以使用 maven/Gradle 插件直接将库添加到您的 JAR/WAR 中。

胖罐子 - http://tutorials.jenkov.com/maven/maven-build-fat-jar.html WAR - 您的依赖项会自动打包

我不建议使用 Fat JAR/WAR 解决方案,因为添加更多插件可能会迷失在依赖项中并出现错误,例如重复依赖类的情况。

【讨论】:

感谢 @marcel 抽出宝贵时间撰写如此广泛的回复。我终于走了耳朵的路径。主要是因为我在 github 中找到了专门针对 Keycloak 的示例,它们解决了同样的问题。 github.com/dteleguin/beercloakgithub.com/zak905/keycloak-api-key-demokeycloak.discourse.group/t/…

以上是关于在 wildfly jar 中包含第三方库(keycloak SPI)的主要内容,如果未能解决你的问题,请参考以下文章

在打包的 JAR 中包含本地依赖项 [重复]

使用亚马逊弹性mapreduce服务时如何在hadoop中包含第三方库

使用 Maven 在可执行 JAR 中包含签名库

Maven - 在 jar 中包含依赖库而不解包依赖项?

如何使用 Eclipse 中包含的外部库创建 jar?

如何防止 ProGuard 在输出 jar 中包含引用的库