[英]Running fat jar vs sbt run
我有一个运行以下代码的 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. }
我将使用sbt assembly
创建一个 uber/fat jar。 然后我将使用命令java -jar app.jar
。 结果是以下异常
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)
上述错误是从line 8
抛出的。
我将执行sbt run
并且我看不到任何错误。 该应用程序运行得很好。
我尝试过的事情:
sbt run
和java -jar
可能 jar 不包含相关类(BasicAuthCredentialProvider)。 我验证了jar -tf
infact 确实存在这些类。 如果该类不存在,我会怀疑 ClassNotFound 异常。JAVA_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005" sbt run
和java -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
。 我的想法是找出实际发生的事情。 我在这里得到了一些有趣的结果。 我单步执行代码,看到这一行ServiceLoader<HttpCredentialProvider> providers = ServiceLoader.load(HttpCredentialProvider.class, BasicAuthCredentialProvider.class.getClassLoader());
调用使用一些反射的ServiceLoader.load
public static <S> ServiceLoader<S> load(Class<S> service,
ClassLoader loader)
{
return new ServiceLoader<>(Reflection.getCallerClass(), service, loader);
}
这就是我被完全阻止的地方。 我想了解导致问题的原因,但我不确定如何通过反射问题进行调试(如果问题是什么)。 运行sbt run
,代码会执行与上述代码存在的同一类中的另一个函数。 此函数称为loadBasicAuthCredentialProvider
。 但是,该函数永远不会被java -jar
调用。 这告诉我反射在这里发挥了一些作用。
如果有人有其他想法,我可以尝试调试此问题,那就太好了!
谢谢!
我想到了! 修复是在程序集的合并策略中。 它看起来像这样:
assemblyMergeStrategy in assembly := {
case PathList("META-INF", xs@_*) => MergeStrategy.discard
case _ => MergeStrategy.first
}
我们需要确保为服务添加了 META-INF。 所以它需要看起来像这样。
assemblyMergeStrategy in assembly := {
case PathList("META-INF", "services", xs@_*) =>
MergeStrategy.first
case PathList("META-INF", xs@_*) =>
MergeStrategy.discard
case x =>
MergeStrategy.first
}
我通过KAFKA-8340找到了答案!
请注意,该调用加载的服务不包括插件目录中 JAR 中包含的 META-INF/services/... 文件中描述的服务
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.