[英]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:我尝试过的事情:
sbt run
and java -jar
perhaps the jar does not contain relevant classes (BasicAuthCredentialProvider).sbt run
和java -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.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 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
。 I idea was to find out what could be actually happening.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.这告诉我反射在这里发挥了一些作用。
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.