JBoss7:使用自定义 HttpRequestInterceptor 的 ReastEasy 和 httpclient 违反加载器约束

问题描述 投票:0回答:5

我在带有 JBoss-7.1.1-Final 的

@Named @ViewScoped
Bean 中使用 RestEasy 客户端框架,通过自定义
HttpRequestInterceptor
:

从 REST 服务检索数据
RegisterBuiltin.register(ResteasyProviderFactory.getInstance());

DefaultHttpClient httpClient = new DefaultHttpClient();
httpClient.addRequestInterceptor(new PreemptiveAuthInterceptor("test","test"), 0);

ClientExecutor clientExecutor = new ApacheHttpClient4Executor(httpClient); //<---

//The error occurs above, the code below is only for completeness
MyRest rest = ProxyFactory.create(MyRest.class,
                                    "http://localhost:8080/rest",clientExecutor);

这在独立客户端应用程序中工作得很好(当我删除

ClientExecutor
时也可以,但我需要它来验证 REST 服务)。该 bean 位于
WAR
内的
EAR
模块中,resteasy 的依赖层次结构解析为以下内容:

Resteasy dependency

httpclient
httpcore
中没有
WAR
EAR
。在 Bean 内部,我遇到以下异常:

java.lang.NoClassDefFoundError: org/apache/http/HttpRequestInterceptor

似乎很容易(尽管我想知道resteasy包装),我添加了

org.apache.httpcomponents:httpclient
compile范围:

enter image description here

不,我遇到了以下异常:

java.lang.LinkageError: loader constraint violation: when resolving method   
  "org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor.<init>    
  (Lorg/apache/http/client/HttpClient;)V"
  the class loader (instance of org/jboss/modules/ModuleClassLoader)
      of the current class, my/TestBean, and
  the class loader (instance of org/jboss/modules/ModuleClassLoader)
      for resolved class, 
  org/jboss/resteasy/client/core/executors/ApacheHttpClient4Executor,
  have different Class objects for the type org/apache/http/client/HttpClient
  used in the signature my.TestBean.init(TestBean.java:65)

更新 要重现此问题,您不需要 REST 接口,实例化

ApacheHttpClient4Executor
时会发生错误,但您可能需要自定义
PreemptiveAuthInterceptor
:

public class PreemptiveAuthInterceptor implements HttpRequestInterceptor
{
  private String username;
  private String password;

  public PreemptiveAuthInterceptor(String username, String password)
  {
    this.username=username;
    this.password=password;
  }

  @Override
  public void process(org.apache.http.HttpRequest request, HttpContext context) throws HttpException, IOException
  {
    AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);

    authState.setAuthScope(org.apache.http.auth.AuthScope.ANY);
    authState.setCredentials(new UsernamePasswordCredentials(username,password));
    authState.setAuthScheme(new BasicScheme());

  }
}
java classloader jboss7.x resteasy
5个回答
10
投票

为了避免在 JBoss 上部署应用程序时发生链接错误,请在 JBoss 安装的模块文件夹中配置模块

org.apache.httpcomponents
,但避免将 HttpComponents 中的 JAR 包含在您的应用程序中:

  1. 将 HttpComponents 中所需的 JAR 放入
    modules/org/apache/httpcomponents/main
  2. 在此目录中的
    module.xml
    中列出这些 JAR。
  3. Dependencies: org.apache.httpcomponents
    添加到组件的
    MANIFEST.MF

请注意,步骤 1 和 2 中引用的模块已经存在。但是,您可能想要包含其他 JARS(例如

httpclient-cache-x.y.z.jar
)或不同版本。

在您的开发环境中解决类是另一回事。


7
投票

我在类似的情况下也遇到了同样的问题。所需的 HttpComponents 模块已位于我的 JBoss (AS 7.1.1) 模块目录中。因此,要解决这个问题,我所要做的就是按照 Eustachius 的描述添加一个清单条目,在 Maven 中你可以这样做:

<build>
    <plugins>
        <plugin>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <archive>
                    <manifestEntries>
                        <Dependencies>org.apache.httpcomponents</Dependencies>
                    </manifestEntries>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>

maven-war-plugin 的配置相同。


2
投票

如果 Arquillian 测试中需要模块......

使用以下内容在 src/test/resources 中创建 arquillian-manifest.mf:

Manifest-Version: 1.0
Dependencies: org.jboss.resteasy.resteasy-jaxrs,org.apache.httpcomponents

然后当你ShrinkWrap时:

WebArchive war = ShrinkWrap.create...
    .addAsManifestResource("arquillian-manifest.mf", "MANIFEST.MF")

0
投票

但是将依赖项:org.apache.httpcomponents 添加到组件的 MANIFEST.MF 中。

导致异常 - 引起原因:java.lang.IllegalStateException:JBAS014744:找不到 org.apache.httpcomponents:main 的 META-INF/services/org.jboss.as.controller.Extension 在 org.jboss.as.controller.parsing.ExtensionXml.loadModule(ExtensionXml.java:191) [jboss-as-controller-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8]


0
投票

最后我的最终方法:

  • resteasy-jaxrs
    定义为
    provided
    依赖项,与
    httpcomponents:httpclient
  • 相同
  • 使用
    copy-dependency
    jib
    maven 插件将更高版本的
    resteasy-jaxrs
    jar 及其依赖项复制到
    main
    resteasy-jaxrs
    插槽(要查找所需的其他 jar,请检查
    module.xml
    中的原始
    main
    )基础镜像/服务器的插槽,并根据需要进行升级;在
    pom.xml
    中将它们定义为
    runtime
    依赖项,因为您不需要它们进行编译,只需要复制 jar
  • 对更高版本的
    httpcomponents:httpclient
    jar 执行相同操作(因为它是
    resteasy-jaxrs
    的隐式依赖)
  • 再次使用
    jib
    插件,覆盖两个
    modules.xml
    插槽中的
    main
    以指向更高版本的 jar 文件名

确保复制 jar 发生在 jib 构建镜像之前的 Maven 构建阶段。例如,

prepare-package
package
之前。

我的理论是,

resteasy-jaxrs
是JBoss EAP服务器的隐式依赖,它们的类加载器具有最高优先级,因此它们会首先加载他们想要的类,并且仅加载
main
槽,然后再加载任何显式依赖/jboss-deployment-struct.xml 依赖项/其他。所以我唯一的办法就是改变
main
插槽。

© www.soinside.com 2019 - 2024. All rights reserved.