-
Couldn't load subscription status.
- Fork 38.8k
Description
Hello, I used Spring boot3.4.4 + spring cloud2024.0.1 + graalvm17.0.14 to build native image, I configured Webclient as follows
@Configuration(proxyBeanMethods = false)
@Slf4j
public class UserClientConfig extends WebClientCommonConfig {
@Autowired
private ReactorLoadBalancerExchangeFilterFunction reactorLoadBalancerExchangeFilterFunction;
@Bean(name = "userClient")
@ConditionalOnMissingBean(name = "userClient")
public UserClient userClient() {
log.info("====================org.graalvm.nativeimage.imagecode=={}==",System.getProperty("org.graalvm.nativeimage.imagecode"));
log.info("============spring.aot.enabled=============={}", SpringProperties.getFlag("spring.aot.enabled"));
WebClient webClient = WebClient.builder()
.baseUrl("http://" + clientName)
.filters(exchangeFilterFunctions -> {
exchangeFilterFunctions.add(reactorLoadBalancerExchangeFilterFunction);
exchangeFilterFunctions.add(recordCostTime());
})
// .defaultHeaders(header -> {
// header.setBasicAuth("admin", "1qaz@WSX#EDC");
// })
.codecs(codecConfig -> {
// codecConfig.registerDefaults(false);
//注销默认json编码解码器 使用自定义编码解码器
codecConfig.defaultCodecs().jackson2JsonEncoder(null);
codecConfig.defaultCodecs().jackson2JsonDecoder(null);
codecConfig.customCodecs()
.register(new Jackson2JsonEncoder(new ObjectMapper(), MediaType.APPLICATION_JSON));
codecConfig.customCodecs()
.register(new Jackson2JsonDecoder(new ObjectMapper(), MediaType.APPLICATION_JSON));
//注销默认xml编码解码器 使用自定义编码解码器
codecConfig.defaultCodecs().jaxb2Encoder(null);
codecConfig.defaultCodecs().jaxb2Decoder(null);
codecConfig.customCodecs()
.encoder(new Jackson2XmlEncoder(new XmlMapper(), MediaType.APPLICATION_XML));
codecConfig.customCodecs()
.decoder(new Jackson2XmlDecoder(new XmlMapper(), MediaType.APPLICATION_XML));
})
// .maxInMemorySize(100)
// .filter()
//编解码器对内存缓冲区的数据限制 默认256k
.exchangeStrategies(ExchangeStrategies.builder()
.codecs(configurer -> configurer.defaultCodecs()
.maxInMemorySize(16 * 1024 * 1024)
)
.build())
.observationRegistry(observationRegistry)
.defaultStatusHandler(HttpStatusCode::isError, response -> processResponse(response))
.build();
HttpServiceProxyFactory factory =
HttpServiceProxyFactory
.builderFor(WebClientAdapter.create(webClient))
.build();
return factory.createClient(UserClient.class);
}
}
when run demo-rective, and call api, it caused exception as follows:
java.lang.IllegalArgumentException: Object of class [org.springframework.context.support.GenericApplicationContext] must be an instance of interface org.springframework.context.annotation.AnnotationConfigRegistry
at org.springframework.util.Assert.instanceCheckFailed(Assert.java:618)
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Assembly trace from producer [reactor.core.publisher.MonoDefer] :
reactor.core.publisher.Mono.defer(Mono.java:219)
org.springframework.web.reactive.function.client.DefaultWebClient$DefaultRequestBodyUriSpec.lambda$exchange$12(DefaultWebClient.java:467)
Error has been observed at the following site(s):
*____________Mono.defer ⇢ at org.springframework.web.reactive.function.client.DefaultWebClient$DefaultRequestBodyUriSpec.lambda$exchange$12(DefaultWebClient.java:467)
|_ checkpoint ⇢ Request to POST http://USER-SERVICE/user/getUserInfo2 [DefaultWebClient]
|_ Mono.switchIfEmpty ⇢ at org.springframework.web.reactive.function.client.DefaultWebClient$DefaultRequestBodyUriSpec.lambda$exchange$12(DefaultWebClient.java:472)
|_ Mono.doOnNext ⇢ at org.springframework.web.reactive.function.client.DefaultWebClient$DefaultRequestBodyUriSpec.lambda$exchange$12(DefaultWebClient.java:478)
|_ Mono.doOnError ⇢ at org.springframework.web.reactive.function.client.DefaultWebClient$DefaultRequestBodyUriSpec.lambda$exchange$12(DefaultWebClient.java:479)
|_ Mono.doFinally ⇢ at org.springframework.web.reactive.function.client.DefaultWebClient$DefaultRequestBodyUriSpec.lambda$exchange$12(DefaultWebClient.java:480)
|_ Mono.contextWrite ⇢ at org.springframework.web.reactive.function.client.DefaultWebClient$DefaultRequestBodyUriSpec.lambda$exchange$12(DefaultWebClient.java:486)
*__Mono.deferContextual ⇢ at org.springframework.web.reactive.function.client.DefaultWebClient$DefaultRequestBodyUriSpec.exchange(DefaultWebClient.java:453)
|_ Mono.flatMap ⇢ at org.springframework.web.reactive.function.client.DefaultWebClient$DefaultResponseSpec.bodyToMono(DefaultWebClient.java:587)
|_ Mono.cache ⇢ at cn.edu.hhu.service.UserLoginService.login2(UserLoginService.java:124)
|_ Mono.flatMap ⇢ at cn.edu.hhu.service.UserLoginService.login2(UserLoginService.java:128)
|_ Mono.tap ⇢ at cn.edu.hhu.aspect.LogAspect.aroundController1(LogAspect.java:95)
|_ Mono.doOnSuccess ⇢ at cn.edu.hhu.aspect.LogAspect.aroundController1(LogAspect.java:96)
Original Stack Trace:
at org.springframework.util.Assert.instanceCheckFailed(Assert.java:618)
at org.springframework.util.Assert.isInstanceOf(Assert.java:513)
at org.springframework.util.Assert.isInstanceOf(Assert.java:546)
at org.springframework.cloud.context.named.NamedContextFactory.registerBeans(NamedContextFactory.java:144)
at org.springframework.cloud.context.named.NamedContextFactory.createContext(NamedContextFactory.java:138)
at org.springframework.cloud.context.named.NamedContextFactory.getContext(NamedContextFactory.java:123)
at org.springframework.cloud.context.named.NamedContextFactory.getInstances(NamedContextFactory.java:254)
at org.springframework.cloud.client.loadbalancer.reactive.ReactorLoadBalancerExchangeFilterFunction.filter(ReactorLoadBalancerExchangeFilterFunction.java:83)
at org.springframework.web.reactive.function.client.ExchangeFilterFunction.lambda$andThen$1(ExchangeFilterFunction.java:62)
at org.springframework.web.reactive.function.client.ExchangeFilterFunction.lambda$andThen$1(ExchangeFilterFunction.java:62)
at org.springframework.web.reactive.function.client.ExchangeFilterFunction.lambda$andThen$1(ExchangeFilterFunction.java:62)
at org.springframework.web.reactive.function.client.ExchangeFilterFunction.lambda$andThen$1(ExchangeFilterFunction.java:62)
at org.springframework.web.reactive.function.client.ExchangeFilterFunction.lambda$andThen$1(ExchangeFilterFunction.java:62)
at org.springframework.web.reactive.function.client.ExchangeFilterFunction.lambda$andThen$1(ExchangeFilterFunction.java:62)
at org.springframework.web.reactive.function.client.ExchangeFilterFunction.lambda$andThen$1(ExchangeFilterFunction.java:62)
at org.springframework.web.reactive.function.client.ExchangeFilterFunction.lambda$apply$2(ExchangeFilterFunction.java:73)
at org.springframework.web.reactive.function.client.DefaultWebClient$DefaultRequestBodyUriSpec.lambda$exchange$8(DefaultWebClient.java:468)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:45)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76)
at reactor.core.publisher.MonoContextWriteRestoringThreadLocals.subscribe(MonoContextWriteRestoringThreadLocals.java:44)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76)
at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:55)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76)
at reactor.core.publisher.MonoCacheTime.subscribeOrReturn(MonoCacheTime.java:143)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:63)
at reactor.core.publisher.MonoTapRestoringThreadLocals.subscribe(MonoTapRestoringThreadLocals.java:77)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76)
at reactor.core.publisher.MonoContextWriteRestoringThreadLocals.subscribe(MonoContextWriteRestoringThreadLocals.java:44)
at reactor.core.publisher.Mono.subscribe(Mono.java:4576)
at reactor.core.publisher.Mono.subscribeWith(Mono.java:4641)
at reactor.core.publisher.Mono.subscribe(Mono.java:4403)
at cn.edu.hhu.aspect.LogAspect.aroundController1(LogAspect.java:116)
at [email protected]/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:642)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:632)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727)
at cn.edu.hhu.controller.UserLoginController$$SpringCGLIB$$0.login2(<generated>)
at [email protected]/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.web.reactive.result.method.InvocableHandlerMethod.lambda$invoke$0(InvocableHandlerMethod.java:208)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:132)
at reactor.core.publisher.MonoZip$ZipCoordinator.signal(MonoZip.java:297)
at reactor.core.publisher.MonoZip$ZipInner.onNext(MonoZip.java:478)
at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onNext(MonoPeekTerminal.java:180)
at reactor.core.publisher.FluxDefaultIfEmpty$DefaultIfEmptySubscriber.onNext(FluxDefaultIfEmpty.java:122)
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onNext(FluxPeekFuseable.java:210)
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:74)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:158)
at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onNext(FluxContextWrite.java:107)
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onNext(FluxMapFuseable.java:299)
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.onNext(FluxFilterFuseable.java:337)
at reactor.core.publisher.Operators$BaseFluxToMonoOperator.completePossiblyEmpty(Operators.java:2097)
at reactor.core.publisher.MonoCollect$CollectSubscriber.onComplete(MonoCollect.java:145)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onComplete(FluxMapFuseable.java:152)
at reactor.core.publisher.FluxContextWriteRestoringThreadLocalsFuseable$FuseableContextWriteRestoringThreadLocalsSubscriber.onComplete(FluxContextWriteRestoringThreadLocalsFuseable.java:150)
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableConditionalSubscriber.onComplete(FluxPeekFuseable.java:595)
at reactor.core.publisher.FluxContextWriteRestoringThreadLocalsFuseable$FuseableContextWriteRestoringThreadLocalsSubscriber.onComplete(FluxContextWriteRestoringThreadLocalsFuseable.java:150)
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onComplete(FluxMapFuseable.java:350)
at reactor.core.publisher.FluxContextWriteRestoringThreadLocals$ContextWriteRestoringThreadLocalsSubscriber.onComplete(FluxContextWriteRestoringThreadLocals.java:149)
at reactor.netty.channel.FluxReceive.terminateReceiver(FluxReceive.java:481)
at reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:273)
at reactor.netty.channel.FluxReceive.request(FluxReceive.java:131)
at reactor.core.publisher.FluxContextWriteRestoringThreadLocals$ContextWriteRestoringThreadLocalsSubscriber.request(FluxContextWriteRestoringThreadLocals.java:163)
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.request(FluxMapFuseable.java:360)
at reactor.core.publisher.FluxContextWriteRestoringThreadLocalsFuseable$FuseableContextWriteRestoringThreadLocalsSubscriber.request(FluxContextWriteRestoringThreadLocalsFuseable.java:164)
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableConditionalSubscriber.request(FluxPeekFuseable.java:437)
at reactor.core.publisher.FluxContextWriteRestoringThreadLocalsFuseable$FuseableContextWriteRestoringThreadLocalsSubscriber.request(FluxContextWriteRestoringThreadLocalsFuseable.java:164)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:171)
at reactor.core.publisher.Operators$BaseFluxToMonoOperator.request(Operators.java:2067)
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.request(FluxFilterFuseable.java:411)
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.request(FluxMapFuseable.java:360)
at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.request(FluxContextWrite.java:136)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2367)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onSubscribe(FluxOnErrorResume.java:74)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117)
at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onSubscribe(FluxContextWrite.java:101)
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onSubscribe(FluxMapFuseable.java:265)
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.onSubscribe(FluxFilterFuseable.java:305)
at reactor.core.publisher.Operators$BaseFluxToMonoOperator.onSubscribe(Operators.java:2051)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:96)
at reactor.core.publisher.FluxContextWriteRestoringThreadLocalsFuseable$FuseableContextWriteRestoringThreadLo
I investigated the source code, I found in the method of filter of ReactorLoadBalancerExchangeFilterFunction to get server instance by loadblance , the type of AbstractApplicationContext is GenericApplicationContext, not implements AnnotationConfigRegistry , so it caused org.springframework.context.support.GenericApplicationContext must be an instance of interface org.springframework.context.annotation.AnnotationConfigRegistry by Assert.isInstanceOf(AnnotationConfigRegistry.class, context);
the source code as follows:
public class ReactorLoadBalancerExchangeFilterFunction implements LoadBalancedExchangeFilterFunction {
@Override
public Mono<ClientResponse> filter(ClientRequest clientRequest, ExchangeFunction next) {
Set<LoadBalancerLifecycle> supportedLifecycleProcessors = LoadBalancerLifecycleValidator
.getSupportedLifecycleProcessors(**loadBalancerFactory.getInstances(**serviceId, LoadBalancerLifecycle.class),
RequestDataContext.class, ResponseData.class, ServiceInstance.class);
}
}
public abstract class NamedContextFactory<C extends NamedContextFactory.Specification>
implements DisposableBean, ApplicationContextAware {
public <T> Map<String, T> getInstances(String name, Class<T> type) {
GenericApplicationContext context = **getContext(name);**
return BeanFactoryUtils.beansOfTypeIncludingAncestors(context, type);
}
protected GenericApplicationContext getContext(String name) {
if (!this.contexts.containsKey(name)) {
synchronized (this.contexts) {
if (!this.contexts.containsKey(name)) {
this.contexts.put(name, **createContext(name)**);
}
}
}
return this.contexts.get(name);
}
public GenericApplicationContext createContext(String name) {
GenericApplicationContext context = **buildContext**(name);
// there's an AOT initializer for this context
if (applicationContextInitializers.get(name) != null) {
applicationContextInitializers.get(name).initialize(context);
context.refresh();
return context;
}
**registerBeans(name, context);**
context.refresh();
return context;
}
public GenericApplicationContext buildContext(String name) {
// https://github.com/spring-cloud/spring-cloud-netflix/issues/3101
// https://github.com/spring-cloud/spring-cloud-openfeign/issues/475
ClassLoader classLoader = getClass().getClassLoader();
GenericApplicationContext context;
if (this.parent != null) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
if (parent instanceof ConfigurableApplicationContext) {
beanFactory.setBeanClassLoader(
((ConfigurableApplicationContext) parent).getBeanFactory().getBeanClassLoader());
}
else {
beanFactory.setBeanClassLoader(classLoader);
}
context = AotDetector.useGeneratedArtifacts() ? new GenericApplicationContext(beanFactory)
: new AnnotationConfigApplicationContext(beanFactory);
}
else {
context = **AotDetector.useGeneratedArtifacts()** ? new GenericApplicationContext()
: new AnnotationConfigApplicationContext();
}
context.setClassLoader(classLoader);
context.getEnvironment()
.getPropertySources()
.addFirst(
new MapPropertySource(this.propertySourceName, Collections.singletonMap(this.propertyName, name)));
if (this.parent != null) {
// Uses Environment from parent as well as beans
context.setParent(this.parent);
}
context.setDisplayName(generateDisplayName(name));
return context;
}
public void registerBeans(String name, GenericApplicationContext context) {
**Assert.isInstanceOf(AnnotationConfigRegistry.class, context);**
AnnotationConfigRegistry registry = (AnnotationConfigRegistry) context;
if (this.configurations.containsKey(name)) {
for (Class<?> configuration : this.configurations.get(name).getConfiguration()) {
registry.register(configuration);
}
}
for (Map.Entry<String, C> entry : this.configurations.entrySet()) {
if (entry.getKey().startsWith("default.")) {
for (Class<?> configuration : entry.getValue().getConfiguration()) {
registry.register(configuration);
}
}
}
registry.register(PropertyPlaceholderAutoConfiguration.class, this.defaultConfigType);
}
}
public abstract class AotDetector {
public static final String AOT_ENABLED = "spring.aot.enabled";
private static final boolean inNativeImage = NativeDetector.inNativeImage(Context.RUN, Context.BUILD);
// when native image runs, this return true
public static boolean **useGeneratedArtifacts**() {
return (inNativeImage || SpringProperties.getFlag(AOT_ENABLED));
}
}
so how to resolve this problem, thanks