spring-cloud/spring-cloud-commons

BeanPostProcessorChecker [loadBalancerWebClientBuilderBeanPostProcessor] is declared through a non-static factory method on that class

c-hui opened this issue · 4 comments

Version:

  • spring boot: 3.2.2
  • spring cloud: 2023.0.0
  • spring cloud commons: 4.1.1

description:

when startup, have warn messages :

2024-02-21 18:36:11.084 [main] WARN  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker - Bean 'org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerBeanPostProcessorAutoConfiguration' of type [org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerBeanPostProcessorAutoConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). The currently created BeanPostProcessor [loadBalancerWebClientBuilderBeanPostProcessor] is declared through a non-static factory method on that class; consider declaring it as static instead.
2024-02-21 18:36:11.087 [main] WARN  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker - Bean 'org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerBeanPostProcessorAutoConfiguration$ReactorDeferringLoadBalancerFilterConfig' of type [org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerBeanPostProcessorAutoConfiguration$ReactorDeferringLoadBalancerFilterConfig] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [loadBalancerWebClientBuilderBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies.
2024-02-21 18:36:11.089 [main] WARN  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker - Bean 'reactorDeferringLoadBalancerExchangeFilterFunction' of type [org.springframework.cloud.client.loadbalancer.reactive.DeferringLoadBalancerExchangeFilterFunction] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [loadBalancerWebClientBuilderBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies.

I see it is indeed non-static here: https://github.com/spring-cloud/spring-cloud-commons/blob/v4.1.1/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/LoadBalancerBeanPostProcessorAutoConfiguration.java#L50

I also encountered the same problem, I used the webflux framework and turned on loadbalancer.

springcloud2023.0.0 spring-cloud-commons4.1.1 springboot(spring-boot-starter-webflux)3.2.3

image

trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerBeanPostProcessorAutoConfiguration' of type [org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerBeanPostProcessorAutoConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). The currently created BeanPostProcessor [loadBalancerWebClientBuilderBeanPostProcessor] is declared through a non-static factory method on that class; consider declaring it as static instead.

trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerBeanPostProcessorAutoConfiguration$ReactorDeferringLoadBalancerFilterConfig' of type [org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerBeanPostProcessorAutoConfiguration$ReactorDeferringLoadBalancerFilterConfig] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [loadBalancerWebClientBuilderBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies.

trationDelegate$BeanPostProcessorChecker : Bean 'reactorDeferringLoadBalancerExchangeFilterFunction' of type [org.springframework.cloud.client.loadbalancer.reactive.DeferringLoadBalancerExchangeFilterFunction] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [loadBalancerWebClientBuilderBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies.

After tracking down, I found that the initialization order of these two classes was not as expected. In fact, 'LoadBalancerBeanPostProcessorAutoConfiguration' was initialized before 'LoadBalancerAutoConfiguration'.

image

I currently have a solution. Exclude this automation configuration 'org.springframework.cloud. Client.loadbalancer.reactive.LoadBalancerBeanPostProcessorAutoConfiguration', customize an automation configuration of 'WebClient. Builder', and add the processing in the 'LoadBalancerWebClientBuilderBeanPostProcessor' to the custom 'WebClient. Builder' configuration.

package org.springframework.cloud.client.loadbalancer.reactive;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.web.reactive.function.client.WebClient;

/**
 * An auto-configuration that provides a {@link BeanPostProcessor} that allows the use of
 * a {@link LoadBalanced} {@link WebClient.Builder} with
 * {@link ReactorLoadBalancerExchangeFilterFunction} and {@link ReactiveLoadBalancer} used
 * under the hood. NOTE: This has been extracted to a separate configuration in order to
 * not impact instantiation and post-processing of other Reactor-LoadBalancer-related
 * beans.
 *
 * @author Olga Maciaszek-Sharma
 * @since 2.2.0
 */
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(WebClient.class)
@Conditional(LoadBalancerBeanPostProcessorAutoConfiguration.OnAnyLoadBalancerImplementationPresentCondition.class)
public class LoadBalancerBeanPostProcessorAutoConfiguration {

	@Bean
	public LoadBalancerWebClientBuilderBeanPostProcessor loadBalancerWebClientBuilderBeanPostProcessor(
			DeferringLoadBalancerExchangeFilterFunction deferringExchangeFilterFunction, ApplicationContext context) {
		return new LoadBalancerWebClientBuilderBeanPostProcessor(deferringExchangeFilterFunction, context);
	}

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnBean(ReactiveLoadBalancer.Factory.class)
	protected static class ReactorDeferringLoadBalancerFilterConfig {

		@Bean
		@Primary
		DeferringLoadBalancerExchangeFilterFunction<LoadBalancedExchangeFilterFunction> reactorDeferringLoadBalancerExchangeFilterFunction(
				ObjectProvider<LoadBalancedExchangeFilterFunction> exchangeFilterFunctionProvider) {
			return new DeferringLoadBalancerExchangeFilterFunction<>(exchangeFilterFunctionProvider);
		}

	}

	static final class OnAnyLoadBalancerImplementationPresentCondition extends AnyNestedCondition {

		private OnAnyLoadBalancerImplementationPresentCondition() {
			super(ConfigurationPhase.REGISTER_BEAN);
		}

		@ConditionalOnBean(ReactiveLoadBalancer.Factory.class)
		static class ReactiveLoadBalancerFactoryPresent {

		}

		@ConditionalOnBean(LoadBalancerClient.class)
		static class LoadBalancerClientPresent {

		}

	}

}
package org.springframework.cloud.client.loadbalancer.reactive;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.ApplicationContext;
import org.springframework.web.reactive.function.client.WebClient;

/**
 * A {@link BeanPostProcessor} that applies
 * {@link DeferringLoadBalancerExchangeFilterFunction} filter to all
 * {@link WebClient.Builder} instances annotated with {@link LoadBalanced}.
 *
 * @author Olga Maciaszek-Sharma
 * @since 2.2.0
 */
public class LoadBalancerWebClientBuilderBeanPostProcessor implements BeanPostProcessor {

	private final DeferringLoadBalancerExchangeFilterFunction exchangeFilterFunction;

	private final ApplicationContext context;

	public LoadBalancerWebClientBuilderBeanPostProcessor(
			DeferringLoadBalancerExchangeFilterFunction exchangeFilterFunction, ApplicationContext context) {
		this.exchangeFilterFunction = exchangeFilterFunction;
		this.context = context;
	}

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		if (bean instanceof WebClient.Builder) {
			if (context.findAnnotationOnBean(beanName, LoadBalanced.class) == null) {
				return bean;
			}
			((WebClient.Builder) bean).filter(exchangeFilterFunction);
		}
		return bean;
	}

}

The customized configuration of 'WebClient. Builder':

package com.conwayd.common.web.configs;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration;
import org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration;
import org.springframework.boot.web.reactive.function.client.WebClientCustomizer;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.client.loadbalancer.reactive.DeferringLoadBalancerExchangeFilterFunction;
import org.springframework.cloud.client.loadbalancer.reactive.LoadBalancedExchangeFilterFunction;
import org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerBeanPostProcessorAutoConfiguration;
import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer;
import org.springframework.cloud.loadbalancer.config.BlockingLoadBalancerClientAutoConfiguration;
import org.springframework.cloud.loadbalancer.config.LoadBalancerAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;
import org.springframework.web.reactive.function.client.WebClient;

/**
 * 自定义webclient
 * <br>
 * 修复框架中 {@link LoadBalancerBeanPostProcessorAutoConfiguration#loadBalancerWebClientBuilderBeanPostProcessor(DeferringLoadBalancerExchangeFilterFunction, ApplicationContext)} 的初始化问题
 *
 * @author conwayD at 2024-03-08 10:27
 * @since 1.0.0
 */
@ConditionalOnClass(WebClient.class)
@Conditional(CustomizeWebClientAutoConfiguration.OnAnyLoadBalancerImplementationPresentCondition.class)
@AutoConfiguration(after = {CodecsAutoConfiguration.class, ClientHttpConnectorAutoConfiguration.class})
@AutoConfigureAfter({LoadBalancerAutoConfiguration.class, BlockingLoadBalancerClientAutoConfiguration.class})
public class CustomizeWebClientAutoConfiguration {

    @Bean
    @Primary
    @Scope("prototype")
    public WebClient.Builder webClientBuilder(ObjectProvider<WebClientCustomizer> customizerProvider,
                                              ObjectProvider<LoadBalancedExchangeFilterFunction> exchangeFilterFunctionProvider) {

        WebClient.Builder builder = WebClient.builder();
        customizerProvider.orderedStream().forEach((customizer) -> customizer.customize(builder));

        DeferringLoadBalancerExchangeFilterFunction<LoadBalancedExchangeFilterFunction> filterFunction =
                new DeferringLoadBalancerExchangeFilterFunction<>(exchangeFilterFunctionProvider);
        builder.filter(filterFunction);

        return builder;
    }

    static final class OnAnyLoadBalancerImplementationPresentCondition extends AnyNestedCondition {

        private OnAnyLoadBalancerImplementationPresentCondition() {
            super(ConfigurationPhase.REGISTER_BEAN);
        }

        @ConditionalOnBean(ReactiveLoadBalancer.Factory.class)
        static class ReactiveLoadBalancerFactoryPresent {

        }

        @ConditionalOnBean(LoadBalancerClient.class)
        static class LoadBalancerClientPresent {

        }

    }
}

Hello @c-hui. Thanks for reporting the issue. This is a duplicate of #1315. Please upgrade to the newest release.