简体   繁体   English

运行 fat jar 与 sbt run

[英]Running fat jar vs sbt run

I have a scala program that runs the following piece of code.我有一个运行以下代码的 Scala 程序。

1.    public static HttpCredentialProvider loadHttpCredentialProviders(String name) {
2.       ServiceLoader<HttpCredentialProvider> providers = ServiceLoader.load(HttpCredentialProvider.class, BasicAuthCredentialProvider.class.getClassLoader());
3.        Iterator var2 = providers.iterator();
4.
5.        HttpCredentialProvider provider;
6.        do {
7.            if (!var2.hasNext()) {
8.                throw new ConfigException("HttpCredentialProvider not found for " + name);
9.            }
10.
11.           provider = (HttpCredentialProvider)var2.next();
12.       } while(!provider.getScheme().equalsIgnoreCase(name));
13.
14.       return provider;
15.   }

I will create an uber/fat jar using sbt assembly .我将使用sbt assembly创建一个 uber/fat jar。 Then I will use the command java -jar app.jar .然后我将使用命令java -jar app.jar The result is the following exception结果是以下异常

Caused by: org.apache.kafka.common.config.ConfigException: HttpCredentialProvider not found for BASIC
    at io.confluent.security.auth.client.provider.BuiltInAuthProviders.loadHttpCredentialProviders(BuiltInAuthProviders.java:56)
    at io.confluent.security.auth.client.rest.RestClient.<init>(RestClient.java:117)
    at io.confluent.security.auth.client.rest.RestClient.<init>(RestClient.java:95)
    at io.confluent.kafka.clients.plugins.auth.token.TokenUserLoginCallbackHandler.configure(TokenUserLoginCallbackHandler.java:67)
    at io.confluent.kafka.clients.plugins.auth.token.AbstractTokenLoginCallbackHandler.configure(AbstractTokenLoginCallbackHandler.java:86)
    at org.apache.kafka.common.security.authenticator.LoginManager.<init>(LoginManager.java:60)
    at org.apache.kafka.common.security.authenticator.LoginManager.acquireLoginManager(LoginManager.java:105)
    at org.apache.kafka.common.network.SaslChannelBuilder.configure(SaslChannelBuilder.java:161)

The above error is thrown from line 8 .上述错误是从line 8抛出的。

I will execute sbt run and I see no error.我将执行sbt run并且我看不到任何错误。 The application runs perfectly fine.该应用程序运行得很好。

Things I tried:我尝试过的事情:

  1. Since the difference is sbt run and java -jar perhaps the jar does not contain relevant classes (BasicAuthCredentialProvider).由于区别在于sbt runjava -jar可能 jar 不包含相关类(BasicAuthCredentialProvider)。 I validated that jar -tf infact does have the classes present.我验证了jar -tf infact 确实存在这些类。 If the class was not present I would suspect a ClassNotFound exception.如果该类不存在,我会怀疑 ClassNotFound 异常。
  2. Remote debug both modes of running the application using JAVA_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005" sbt run and java -jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005 app.jar .使用JAVA_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005" sbt runjava -jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005 app.jar远程调试两种运行应用程序的模式java -jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005 app.jar I idea was to find out what could be actually happening.我的想法是找出实际发生的事情。 I got some interesting results here.我在这里得到了一些有趣的结果。 I stepped through the code and saw that this line我单步执行代码,看到这一行
ServiceLoader<HttpCredentialProvider> providers = ServiceLoader.load(HttpCredentialProvider.class, BasicAuthCredentialProvider.class.getClassLoader());

calls the ServiceLoader.load which working with some reflection调用使用一些反射的ServiceLoader.load

public static <S> ServiceLoader<S> load(Class<S> service,
                                            ClassLoader loader)
{
    return new ServiceLoader<>(Reflection.getCallerClass(), service, loader);
}

This is where I am exactly blocked.这就是我被完全阻止的地方。 I want to keeo understanding what is causing the issue but I am not sure how to debug through reflection issues (if that what the problem is).我想了解导致问题的原因,但我不确定如何通过反射问题进行调试(如果问题是什么)。 When running sbt run the code executes another function that exists in the same class the above code exists.运行sbt run ,代码会执行与上述代码存在的同一类中的另一个函数。 This function is called loadBasicAuthCredentialProvider .此函数称为loadBasicAuthCredentialProvider However, that function never gets called by java -jar .但是,该函数永远不会被java -jar调用。 This tells me that the reflection is playing some role here.这告诉我反射在这里发挥了一些作用。

  1. I also switched JAVA version from 8 to 11. No Bueno there either.我还将 JAVA 版本从 8 切换到 11。那里也没有 Bueno。

If anybody has other ideas I could try to debug this issue it would be great!如果有人有其他想法,我可以尝试调试此问题,那就太好了!

Thank you!谢谢!

I figured it out!我想到了! The fix was in the merge strategy for assembly.修复是在程序集的合并策略中。 It looked like this:它看起来像这样:

assemblyMergeStrategy in assembly := {
  case PathList("META-INF", xs@_*) => MergeStrategy.discard
  case _ => MergeStrategy.first
}

We need to make sure META-INF was added for services.我们需要确保为服务添加了 META-INF。 So it needs to look like this.所以它需要看起来像这样。

assemblyMergeStrategy in assembly := {
  case PathList("META-INF", "services", xs@_*) =>
    MergeStrategy.first
  case PathList("META-INF", xs@_*) =>
    MergeStrategy.discard
  case x =>
    MergeStrategy.first
}

I found the answer through KAFKA-8340 !我通过KAFKA-8340找到了答案!

Observe that the services loaded by that invocation do not include the ones described in the META-INF/services/... file contained in the JAR in the plugin's directory请注意,该调用加载的服务不包括插件目录中 JAR 中包含的 META-INF/services/... 文件中描述的服务

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM