Skip to content

ReactorLoadBalancerExchangeFilterFunction caused org.springframework.context.support.GenericApplicationContext must be an instance of interface org.springframework.context.annotation.AnnotationConfigRegistry error in native image #34822

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
yy9991818 opened this issue Apr 25, 2025 · 0 comments
Labels
status: waiting-for-triage An issue we've not yet triaged or decided on

Comments

@yy9991818
Copy link

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

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Apr 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: waiting-for-triage An issue we've not yet triaged or decided on
Projects
None yet
Development

No branches or pull requests

2 participants