quarkus-rest-client 不能与原生图像的@ApplicationScoped beans 一起使用:堆中不允许 sun.security.provider.NativePRNG 的实例
quarkus-rest-client can't be used with @ApplicationScoped beans for native images: No instances of sun.security.provider.NativePRNG allowed in heap
重现此问题的示例项目available on Github
我正在使用 quarkus-rest-client 从我的 Quarkus 应用程序调用 REST 服务。
ExampleResource
提供一个端点 http://localhost:8080/echo
,它使用 RestClient
:
调用 https://postman-echo.com/get
@Path("/echo")
public class ExampleResource {
private final RestClient restClient;
public ExampleResource(RestClient restClient){
this.restClient = restClient;
}
@GET
@Produces(MediaType.TEXT_PLAIN)
public Response get() {
return restClient.get();
}
}
@ApplicationScoped
public class RestClient {
private final Client httpClient;
public RestClient() {
this.httpClient = ResteasyClientBuilder.newBuilder().build();
}
public Response get() {
return httpClient.target("https://postman-echo.com/get").request().get();
}
}
虽然它工作正常,但当我尝试生成原生图像时它失败了:
./mvnw package -Pnative -Dquarkus.native.container-build=true
Error: No instances of sun.security.provider.NativePRNG are allowed in the image heap as this class should be initialized at image runtime. To see how this object got instantiated use -H:+TraceClassInitialization.
Detailed message:
Trace: object java.security.SecureRandom
object sun.security.ssl.SSLContextImpl$TLSContext
object sun.security.ssl.SSLSocketFactoryImpl
object org.apache.http.conn.ssl.SSLConnectionSocketFactory
object java.util.concurrent.ConcurrentHashMap$Node
object java.util.concurrent.ConcurrentHashMap$Node[]
object java.util.concurrent.ConcurrentHashMap
object org.apache.http.config.Registry
object org.apache.http.impl.conn.DefaultHttpClientConnectionOperator
object org.apache.http.impl.conn.PoolingHttpClientConnectionManager
object org.apache.http.impl.client.HttpClientBuilder
object java.lang.Object[]
object java.util.ArrayList
object org.apache.http.impl.client.InternalHttpClient
object org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient43Engine
object org.jboss.resteasy.client.jaxrs.internal.ResteasyClientImpl
object org.codependent.RestClient_ClientProxy
object org.codependent.RestClient_Bean
object java.lang.Object[]
object java.util.ArrayList
object io.quarkus.arc.impl.ArcContainerImpl
object io.quarkus.arc.runtime.ArcRecorder
field io.quarkus.resteasy.common.runtime.QuarkusInjectorFactory.CONTAINER
com.oracle.svm.core.util.UserError$UserException: No instances of sun.security.provider.NativePRNG are allowed in the image heap as this class should be initialized at image runtime. To see how this object got instantiated use -H:+TraceClassInitialization.
Detailed message:
Trace: object java.security.SecureRandom
object sun.security.ssl.SSLContextImpl$TLSContext
object sun.security.ssl.SSLSocketFactoryImpl
object org.apache.http.conn.ssl.SSLConnectionSocketFactory
object java.util.concurrent.ConcurrentHashMap$Node
object java.util.concurrent.ConcurrentHashMap$Node[]
object java.util.concurrent.ConcurrentHashMap
object org.apache.http.config.Registry
object org.apache.http.impl.conn.DefaultHttpClientConnectionOperator
object org.apache.http.impl.conn.PoolingHttpClientConnectionManager
object org.apache.http.impl.client.HttpClientBuilder
object java.lang.Object[]
object java.util.ArrayList
object org.apache.http.impl.client.InternalHttpClient
object org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient43Engine
object org.jboss.resteasy.client.jaxrs.internal.ResteasyClientImpl
object org.codependent.RestClient_ClientProxy
object org.codependent.RestClient_Bean
object java.lang.Object[]
object java.util.ArrayList
object io.quarkus.arc.impl.ArcContainerImpl
object io.quarkus.arc.runtime.ArcRecorder
field io.quarkus.resteasy.common.runtime.QuarkusInjectorFactory.CONTAINER
如果我按照 Quarkus guide regarding this error 中的说明进行操作,在 pom 中添加额外的构建参数仍然会失败:
<quarkus.native.additional-build-args>--initialize-at-run-time=org.codependent.RestClient,-H:+TraceClassInitialization</quarkus.native.additional-build-args>
./mvnw package -Pnative -Dquarkus.native.container-build=true
com.oracle.svm.core.util.UserError$UserException: Classes that should be initialized at run time got initialized during image building:
org.codependent.RestClient the class was requested to be initialized at build time (from the command line). io.quarkus.runner.ApplicationImpl caused initialization of this class with the following trace:
at org.codependent.RestClient.<clinit>(RestClient.java)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at org.codependent.RestClient_Bean.<init>(RestClient_Bean.zig:135)
at io.quarkus.arc.setup.Default_ComponentsProvider.addBeans1(Default_ComponentsProvider.zig:106)
at io.quarkus.arc.setup.Default_ComponentsProvider.getComponents(Default_ComponentsProvider.zig:38)
at io.quarkus.arc.impl.ArcContainerImpl.<init>(ArcContainerImpl.java:103)
at io.quarkus.arc.Arc.initialize(Arc.java:20)
at io.quarkus.arc.runtime.ArcRecorder.getContainer(ArcRecorder.java:35)
at io.quarkus.deployment.steps.ArcProcessor$generateResources20.deploy_0(ArcProcessor$generateResources20.zig:72)
at io.quarkus.deployment.steps.ArcProcessor$generateResources20.deploy(ArcProcessor$generateResources20.zig:36)
at io.quarkus.runner.ApplicationImpl.<clinit>(ApplicationImpl.zig:338)
org.codependent.RestClient_ClientProxy the class was requested to be initialized at build time (subtype of org.codependent.RestClient). io.quarkus.runner.ApplicationImpl caused initialization of this class with the following trace:
at org.codependent.RestClient_ClientProxy.<clinit>(RestClient_ClientProxy.zig)
at org.codependent.RestClient_Bean.<init>(RestClient_Bean.zig:164)
at io.quarkus.arc.setup.Default_ComponentsProvider.addBeans1(Default_ComponentsProvider.zig:106)
at io.quarkus.arc.setup.Default_ComponentsProvider.getComponents(Default_ComponentsProvider.zig:38)
at io.quarkus.arc.impl.ArcContainerImpl.<init>(ArcContainerImpl.java:103)
at io.quarkus.arc.Arc.initialize(Arc.java:20)
at io.quarkus.arc.runtime.ArcRecorder.getContainer(ArcRecorder.java:35)
at io.quarkus.deployment.steps.ArcProcessor$generateResources20.deploy_0(ArcProcessor$generateResources20.zig:72)
at io.quarkus.deployment.steps.ArcProcessor$generateResources20.deploy(ArcProcessor$generateResources20.zig:36)
at io.quarkus.runner.ApplicationImpl.<clinit>(ApplicationImpl.zig:338)
at com.oracle.svm.core.util.UserError.abort(UserError.java:65)
at com.oracle.svm.hosted.classinitialization.ConfigurableClassInitialization.checkDelayedInitialization(ConfigurableClassInitialization.java:510)
at com.oracle.svm.hosted.classinitialization.ClassInitializationFeature.duringAnalysis(ClassInitializationFeature.java:187)
at com.oracle.svm.hosted.NativeImageGenerator.lambda$runPointsToAnalysis(NativeImageGenerator.java:710)
at com.oracle.svm.hosted.FeatureHandler.forEachFeature(FeatureHandler.java:63)
at com.oracle.svm.hosted.NativeImageGenerator.runPointsToAnalysis(NativeImageGenerator.java:710)
at com.oracle.svm.hosted.NativeImageGenerator.doRun(NativeImageGenerator.java:530)
at com.oracle.svm.hosted.NativeImageGenerator.lambda$run[=17=](NativeImageGenerator.java:445)
at java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1386)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
当 RestClient
定义为 @ApplicationScoped
组件时会出现问题 。如果我更改它以便将其实例化,则本机图像生成没有任何问题:
@Path("/echo")
public class ExampleResource {
private final RestClient restClient;
public ExampleResource(){
this.restClient = new RestClient();
}
@GET
@Produces(MediaType.TEXT_PLAIN)
public Response get() {
return restClient.get();
}
}
public class RestClient {
private final Client httpClient;
public RestClient() {
this.httpClient = ResteasyClientBuilder.newBuilder().build();
}
public Response get() {
return httpClient.target("https://postman-echo.com/get").request().get();
}
}
./mvnw package -Pnative -Dquarkus.native.container-build=true
[INFO] [io.quarkus.deployment.QuarkusAugmentor] Quarkus augmentation completed in 72716ms
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:14 min
[INFO] Finished at: 2020-03-21T12:48:07+01:00
[INFO] -
问题是如何将 RestClient
定义为 @ApplicationScoped
组件并能够生成原生图像?
正如回答 here,您没有使用 MicroProfile REST 客户端,而是使用 JAX-RS 客户端。
在任何情况下,您都可以通过将 RestClient
class 更改为:
让您的代码在本机模式下工作
@ApplicationScoped
public class RestClient {
private Client client;
public Response get() {
return getClient().target("https://postman-echo.com/get").request().get();
}
private Client getClient() {
if (client == null) {
client = ResteasyClientBuilder.newBuilder().build();
}
return client;
}
}
并添加:
quarkus.native.enable-https-url-handler=true
到application.properties
重现此问题的示例项目available on Github
我正在使用 quarkus-rest-client 从我的 Quarkus 应用程序调用 REST 服务。
ExampleResource
提供一个端点 http://localhost:8080/echo
,它使用 RestClient
:
https://postman-echo.com/get
@Path("/echo")
public class ExampleResource {
private final RestClient restClient;
public ExampleResource(RestClient restClient){
this.restClient = restClient;
}
@GET
@Produces(MediaType.TEXT_PLAIN)
public Response get() {
return restClient.get();
}
}
@ApplicationScoped
public class RestClient {
private final Client httpClient;
public RestClient() {
this.httpClient = ResteasyClientBuilder.newBuilder().build();
}
public Response get() {
return httpClient.target("https://postman-echo.com/get").request().get();
}
}
虽然它工作正常,但当我尝试生成原生图像时它失败了:
./mvnw package -Pnative -Dquarkus.native.container-build=true
Error: No instances of sun.security.provider.NativePRNG are allowed in the image heap as this class should be initialized at image runtime. To see how this object got instantiated use -H:+TraceClassInitialization.
Detailed message:
Trace: object java.security.SecureRandom
object sun.security.ssl.SSLContextImpl$TLSContext
object sun.security.ssl.SSLSocketFactoryImpl
object org.apache.http.conn.ssl.SSLConnectionSocketFactory
object java.util.concurrent.ConcurrentHashMap$Node
object java.util.concurrent.ConcurrentHashMap$Node[]
object java.util.concurrent.ConcurrentHashMap
object org.apache.http.config.Registry
object org.apache.http.impl.conn.DefaultHttpClientConnectionOperator
object org.apache.http.impl.conn.PoolingHttpClientConnectionManager
object org.apache.http.impl.client.HttpClientBuilder
object java.lang.Object[]
object java.util.ArrayList
object org.apache.http.impl.client.InternalHttpClient
object org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient43Engine
object org.jboss.resteasy.client.jaxrs.internal.ResteasyClientImpl
object org.codependent.RestClient_ClientProxy
object org.codependent.RestClient_Bean
object java.lang.Object[]
object java.util.ArrayList
object io.quarkus.arc.impl.ArcContainerImpl
object io.quarkus.arc.runtime.ArcRecorder
field io.quarkus.resteasy.common.runtime.QuarkusInjectorFactory.CONTAINER
com.oracle.svm.core.util.UserError$UserException: No instances of sun.security.provider.NativePRNG are allowed in the image heap as this class should be initialized at image runtime. To see how this object got instantiated use -H:+TraceClassInitialization.
Detailed message:
Trace: object java.security.SecureRandom
object sun.security.ssl.SSLContextImpl$TLSContext
object sun.security.ssl.SSLSocketFactoryImpl
object org.apache.http.conn.ssl.SSLConnectionSocketFactory
object java.util.concurrent.ConcurrentHashMap$Node
object java.util.concurrent.ConcurrentHashMap$Node[]
object java.util.concurrent.ConcurrentHashMap
object org.apache.http.config.Registry
object org.apache.http.impl.conn.DefaultHttpClientConnectionOperator
object org.apache.http.impl.conn.PoolingHttpClientConnectionManager
object org.apache.http.impl.client.HttpClientBuilder
object java.lang.Object[]
object java.util.ArrayList
object org.apache.http.impl.client.InternalHttpClient
object org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient43Engine
object org.jboss.resteasy.client.jaxrs.internal.ResteasyClientImpl
object org.codependent.RestClient_ClientProxy
object org.codependent.RestClient_Bean
object java.lang.Object[]
object java.util.ArrayList
object io.quarkus.arc.impl.ArcContainerImpl
object io.quarkus.arc.runtime.ArcRecorder
field io.quarkus.resteasy.common.runtime.QuarkusInjectorFactory.CONTAINER
如果我按照 Quarkus guide regarding this error 中的说明进行操作,在 pom 中添加额外的构建参数仍然会失败:
<quarkus.native.additional-build-args>--initialize-at-run-time=org.codependent.RestClient,-H:+TraceClassInitialization</quarkus.native.additional-build-args>
./mvnw package -Pnative -Dquarkus.native.container-build=true
com.oracle.svm.core.util.UserError$UserException: Classes that should be initialized at run time got initialized during image building:
org.codependent.RestClient the class was requested to be initialized at build time (from the command line). io.quarkus.runner.ApplicationImpl caused initialization of this class with the following trace:
at org.codependent.RestClient.<clinit>(RestClient.java)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at org.codependent.RestClient_Bean.<init>(RestClient_Bean.zig:135)
at io.quarkus.arc.setup.Default_ComponentsProvider.addBeans1(Default_ComponentsProvider.zig:106)
at io.quarkus.arc.setup.Default_ComponentsProvider.getComponents(Default_ComponentsProvider.zig:38)
at io.quarkus.arc.impl.ArcContainerImpl.<init>(ArcContainerImpl.java:103)
at io.quarkus.arc.Arc.initialize(Arc.java:20)
at io.quarkus.arc.runtime.ArcRecorder.getContainer(ArcRecorder.java:35)
at io.quarkus.deployment.steps.ArcProcessor$generateResources20.deploy_0(ArcProcessor$generateResources20.zig:72)
at io.quarkus.deployment.steps.ArcProcessor$generateResources20.deploy(ArcProcessor$generateResources20.zig:36)
at io.quarkus.runner.ApplicationImpl.<clinit>(ApplicationImpl.zig:338)
org.codependent.RestClient_ClientProxy the class was requested to be initialized at build time (subtype of org.codependent.RestClient). io.quarkus.runner.ApplicationImpl caused initialization of this class with the following trace:
at org.codependent.RestClient_ClientProxy.<clinit>(RestClient_ClientProxy.zig)
at org.codependent.RestClient_Bean.<init>(RestClient_Bean.zig:164)
at io.quarkus.arc.setup.Default_ComponentsProvider.addBeans1(Default_ComponentsProvider.zig:106)
at io.quarkus.arc.setup.Default_ComponentsProvider.getComponents(Default_ComponentsProvider.zig:38)
at io.quarkus.arc.impl.ArcContainerImpl.<init>(ArcContainerImpl.java:103)
at io.quarkus.arc.Arc.initialize(Arc.java:20)
at io.quarkus.arc.runtime.ArcRecorder.getContainer(ArcRecorder.java:35)
at io.quarkus.deployment.steps.ArcProcessor$generateResources20.deploy_0(ArcProcessor$generateResources20.zig:72)
at io.quarkus.deployment.steps.ArcProcessor$generateResources20.deploy(ArcProcessor$generateResources20.zig:36)
at io.quarkus.runner.ApplicationImpl.<clinit>(ApplicationImpl.zig:338)
at com.oracle.svm.core.util.UserError.abort(UserError.java:65)
at com.oracle.svm.hosted.classinitialization.ConfigurableClassInitialization.checkDelayedInitialization(ConfigurableClassInitialization.java:510)
at com.oracle.svm.hosted.classinitialization.ClassInitializationFeature.duringAnalysis(ClassInitializationFeature.java:187)
at com.oracle.svm.hosted.NativeImageGenerator.lambda$runPointsToAnalysis(NativeImageGenerator.java:710)
at com.oracle.svm.hosted.FeatureHandler.forEachFeature(FeatureHandler.java:63)
at com.oracle.svm.hosted.NativeImageGenerator.runPointsToAnalysis(NativeImageGenerator.java:710)
at com.oracle.svm.hosted.NativeImageGenerator.doRun(NativeImageGenerator.java:530)
at com.oracle.svm.hosted.NativeImageGenerator.lambda$run[=17=](NativeImageGenerator.java:445)
at java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1386)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
当 RestClient
定义为 @ApplicationScoped
组件时会出现问题 。如果我更改它以便将其实例化,则本机图像生成没有任何问题:
@Path("/echo")
public class ExampleResource {
private final RestClient restClient;
public ExampleResource(){
this.restClient = new RestClient();
}
@GET
@Produces(MediaType.TEXT_PLAIN)
public Response get() {
return restClient.get();
}
}
public class RestClient {
private final Client httpClient;
public RestClient() {
this.httpClient = ResteasyClientBuilder.newBuilder().build();
}
public Response get() {
return httpClient.target("https://postman-echo.com/get").request().get();
}
}
./mvnw package -Pnative -Dquarkus.native.container-build=true
[INFO] [io.quarkus.deployment.QuarkusAugmentor] Quarkus augmentation completed in 72716ms
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:14 min
[INFO] Finished at: 2020-03-21T12:48:07+01:00
[INFO] -
问题是如何将 RestClient
定义为 @ApplicationScoped
组件并能够生成原生图像?
正如回答 here,您没有使用 MicroProfile REST 客户端,而是使用 JAX-RS 客户端。
在任何情况下,您都可以通过将 RestClient
class 更改为:
@ApplicationScoped
public class RestClient {
private Client client;
public Response get() {
return getClient().target("https://postman-echo.com/get").request().get();
}
private Client getClient() {
if (client == null) {
client = ResteasyClientBuilder.newBuilder().build();
}
return client;
}
}
并添加:
quarkus.native.enable-https-url-handler=true
到application.properties