SpringBoot3 - Openfeign 4.0 Migration

Openfeign 4.0 Migration

针对Springboot3.0.x,对应的spring-cloud-openfeign的版本为4.0.x,如果你使用spring-cloud-dependencies来管理依赖,需要使用2022.0.x

<spring-cloud-dependencies.version>2022.0.1spring-cloud-dependencies.version>

<spring-cloud-openfeign.version>4.0.1spring-cloud-openfeign.version>

修改pom之后,启动application,不出意外的出现了新的error

Caused by: java.lang.IllegalStateException: No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalancer?
	at org.springframework.cloud.openfeign.FeignClientFactoryBean.loadBalance(FeignClientFactoryBean.java:401) ~[spring-cloud-openfeign-core-4.0.1.jar:4.0.1]
	at org.springframework.cloud.openfeign.FeignClientFactoryBean.getTarget(FeignClientFactoryBean.java:446) ~[spring-cloud-openfeign-core-4.0.1.jar:4.0.1]
	at org.springframework.cloud.openfeign.FeignClientFactoryBean.getObject(FeignClientFactoryBean.java:421) ~[spring-cloud-openfeign-core-4.0.1.jar:4.0.1]
	at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:148) ~[spring-beans-6.0.6.jar:6.0.6]
	at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:90) ~[spring-beans-6.0.6.jar:6.0.6]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1823) ~[spring-beans-6.0.6.jar:6.0.6]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getObjectForBeanInstance(AbstractAutowireCapableBeanFactory

查了一下,网上给出的方案是增加一个新的依赖

    <dependency>
      <groupId>org.springframework.cloudgroupId>
      <artifactId>spring-cloud-starter-loadbalancerartifactId>
    dependency>

加上之后application确实可以顺利启动,但是对我们来说还是存在疑问,首先我们没有使用loadbalance,我们的Url要么是配置文件里指定的虚地址,需要就是作为参数传给Feign的,为什么现在却需要引入loadbalancer?之前我们默认的HttpClient是ApacheClient,现在换成loadbalancer会不会有潜在的风险?

问题排查

首先根据根据异常栈,我们定位到出错的代码FeignClientFactoryBean#getTarget

<T> T getTarget() {
		FeignClientFactory feignClientFactory = beanFactory != null ? beanFactory.getBean(FeignClientFactory.class)
				: applicationContext.getBean(FeignClientFactory.class);
		Feign.Builder builder = feign(feignClientFactory);
		if (!StringUtils.hasText(url) && !isUrlAvailableInConfig(contextId)) {

			if (LOG.isInfoEnabled()) {
				LOG.info("For '" + name + "' URL not provided. Will try picking an instance via load-balancing.");
			}
			if (!name.startsWith("http")) {
				url = "http://" + name;
			}
			else {
				url = name;
			}
			url += cleanPath();
			return (T) loadBalance(builder, feignClientFactory, new HardCodedTarget<>(type, name, url));
		}
		if (StringUtils.hasText(url) && !url.startsWith("http")) {
			url = "http://" + url;
		}
		//、、、
}

getTarget方法就是为我们生成一个FeignClient实例,根据第一个if语句,如果我们没有为Feign配置Url,就会进入loadBalance方法

protected <T> T loadBalance(Feign.Builder builder, FeignClientFactory context, HardCodedTarget<T> target) {
		Client client = getOptional(context, Client.class);
		if (client != null) {
			builder.client(client);
			applyBuildCustomizers(context, builder);
			Targeter targeter = get(context, Targeter.class);
			return targeter.target(this, builder, context, target);
		}

		throw new IllegalStateException(
				"No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalancer?");
	}

根据loadBalance的代码,如果在getOptional为空,就会抛出我们上面见到的异常。
我们将版本回退到Springboot2.7,通过debug发现在这里我们会拿到一个ApacheHttpClient,在3.0却拿到了一个null,难道是需要修改什么配置吗?我们找到openFeign的配置文件,发现没有什么变化,

{
			"name": "spring.cloud.openfeign.httpclient.enabled",
			"type": "java.lang.Boolean",
			"description": "Enables the use of the Apache HTTP Client by Feign.",
			"defaultValue": "true"
		}

最后我们在官网找到了答案:
https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/

Starting with Spring Cloud OpenFeign 4, the Feign Apache HttpClient 4 is no longer supported. We suggest using Apache HttpClient 5 instead.
难怪我们这里一直取不到,OpenFeign不再支持Apache HttpClient 4,需要我们使用Apache HttpClient 5来进行替代

        <dependency>
            <groupId>io.github.openfeigngroupId>
            <artifactId>feign-hc5artifactId>
        dependency>

然后我们移除了loadbalance的依赖,启动application,报错也没有再次出现。

Tips

Apache HttpClient 4 到5并不是能够完全替代的,默认情况下5不再支持TLSv1.1,如果你们还在用1.1需要进行如下配置

@Configuration
public class HT5Configuration {
@Bean
public PoolingHttpClientConnectionManager customeHttpClient () {
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
SSLContexts.createDefault(),
new String[] { "TLSv1.1"}, null, null);
//
// PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
// cm.
return PoolingHttpClientConnectionManagerBuilder.create().setSSLSocketFactory(sslsf).build();
}

你可能感兴趣的:(Spingboot3,feign,java,spring,spring,cloud)