optimize: alibaba-seata: Transfer XID using `feign.RequestInterceptor` (#1946)

* optimize: alibaba-seata: Transfer XID using `feign.RequestInterceptor`

* 移除多余的代码

* imports顺序调整。

* Feign.Builder的默认retryer修改为NEVER_RETRY。

* fix style

* fix style

* Update SeataFeignBuilderBeanPostProcessor.java

* add static
pull/2636/merge
WangLiang/王良 2 years ago committed by GitHub
parent ad9715dfec
commit 3cb9c96203
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,61 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.seata.feign;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.cloud.openfeign.FeignContext;
/**
* @author xiaojing
*/
public class SeataContextBeanPostProcessor implements BeanPostProcessor {
private final BeanFactory beanFactory;
private SeataFeignObjectWrapper seataFeignObjectWrapper;
SeataContextBeanPostProcessor(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof FeignContext && !(bean instanceof SeataFeignContext)) {
return new SeataFeignContext(getSeataFeignObjectWrapper(),
(FeignContext) bean);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
private SeataFeignObjectWrapper getSeataFeignObjectWrapper() {
if (this.seataFeignObjectWrapper == null) {
this.seataFeignObjectWrapper = this.beanFactory
.getBean(SeataFeignObjectWrapper.class);
}
return this.seataFeignObjectWrapper;
}
}

@ -1,45 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.seata.feign;
import java.io.IOException;
import feign.Client;
import feign.Request;
import feign.Response;
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient;
/**
* @author yuhuangbin
*/
public class SeataFeignBlockingLoadBalancerClient
extends FeignBlockingLoadBalancerClient {
public SeataFeignBlockingLoadBalancerClient(Client delegate,
BlockingLoadBalancerClient loadBalancerClient,
SeataFeignObjectWrapper seataFeignObjectWrapper) {
super((Client) seataFeignObjectWrapper.wrap(delegate), loadBalancerClient);
}
@Override
public Response execute(Request request, Request.Options options) throws IOException {
return super.execute(request, options);
}
}

@ -1,35 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.seata.feign;
import feign.Feign;
import org.springframework.beans.factory.BeanFactory;
/**
* @author xiaojing
*/
final class SeataFeignBuilder {
private SeataFeignBuilder() {
}
static Feign.Builder builder(BeanFactory beanFactory) {
return Feign.builder().client(new SeataFeignClient(beanFactory));
}
}

@ -16,30 +16,28 @@
package com.alibaba.cloud.seata.feign;
import feign.Feign;
import feign.Retryer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* @author xiaojing
* @author wang.liang
* @since 2.2.5
*/
public class SeataBeanPostProcessor implements BeanPostProcessor {
private final SeataFeignObjectWrapper seataFeignObjectWrapper;
public class SeataFeignBuilderBeanPostProcessor implements BeanPostProcessor {
SeataBeanPostProcessor(SeataFeignObjectWrapper seataFeignObjectWrapper) {
this.seataFeignObjectWrapper = seataFeignObjectWrapper;
}
private static final Logger LOGGER = LoggerFactory.getLogger(SeataFeignBuilderBeanPostProcessor.class);
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
return this.seataFeignObjectWrapper.wrap(bean);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof Feign.Builder) {
((Feign.Builder) bean).retryer(Retryer.NEVER_RETRY);
LOGGER.info("change the retryer of the bean '{}' to 'Retryer.NEVER_RETRY'", beanName);
}
return bean;
}
}

@ -1,81 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.seata.feign;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import feign.Client;
import feign.Request;
import feign.Response;
import io.seata.core.context.RootContext;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.util.StringUtils;
/**
* @author xiaojing
*/
public class SeataFeignClient implements Client {
private final Client delegate;
private final BeanFactory beanFactory;
private static final int MAP_SIZE = 16;
SeataFeignClient(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
this.delegate = new Client.Default(null, null);
}
SeataFeignClient(BeanFactory beanFactory, Client delegate) {
this.delegate = delegate;
this.beanFactory = beanFactory;
}
@Override
public Response execute(Request request, Request.Options options) throws IOException {
Request modifiedRequest = getModifyRequest(request);
return this.delegate.execute(modifiedRequest, options);
}
private Request getModifyRequest(Request request) {
String xid = RootContext.getXID();
if (StringUtils.isEmpty(xid)) {
return request;
}
Map<String, Collection<String>> headers = new HashMap<>(MAP_SIZE);
headers.putAll(request.headers());
List<String> seataXid = new ArrayList<>();
seataXid.add(xid);
headers.put(RootContext.KEY_XID, seataXid);
return Request.create(request.method(), request.url(), headers, request.body(),
request.charset());
}
}

@ -17,70 +17,27 @@
package com.alibaba.cloud.seata.feign;
import feign.Client;
import feign.Feign;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.openfeign.FeignAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
/**
* @author xiaojing
* @author wang.liang
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Client.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class SeataFeignClientAutoConfiguration {
@Bean
@Scope("prototype")
@ConditionalOnClass(name = "com.netflix.hystrix.HystrixCommand")
@ConditionalOnProperty(name = "feign.hystrix.enabled", havingValue = "true")
Feign.Builder feignHystrixBuilder(BeanFactory beanFactory) {
return SeataHystrixFeignBuilder.builder(beanFactory);
public static SeataFeignBuilderBeanPostProcessor seataFeignBuilderBeanPostProcessor() {
return new SeataFeignBuilderBeanPostProcessor();
}
@Bean
@Scope("prototype")
@ConditionalOnClass(name = "com.alibaba.csp.sentinel.SphU")
@ConditionalOnProperty(name = "feign.sentinel.enabled", havingValue = "true")
Feign.Builder feignSentinelBuilder(BeanFactory beanFactory) {
return SeataSentinelFeignBuilder.builder(beanFactory);
}
@Bean
@ConditionalOnMissingBean
@Scope("prototype")
Feign.Builder feignBuilder(BeanFactory beanFactory) {
return SeataFeignBuilder.builder(beanFactory);
}
@Configuration(proxyBeanMethods = false)
protected static class FeignBeanPostProcessorConfiguration {
@Bean
static SeataBeanPostProcessor seataBeanPostProcessor(
SeataFeignObjectWrapper seataFeignObjectWrapper) {
return new SeataBeanPostProcessor(seataFeignObjectWrapper);
}
@Bean
static SeataContextBeanPostProcessor seataContextBeanPostProcessor(
BeanFactory beanFactory) {
return new SeataContextBeanPostProcessor(beanFactory);
}
@Bean
SeataFeignObjectWrapper seataFeignObjectWrapper(BeanFactory beanFactory) {
return new SeataFeignObjectWrapper(beanFactory);
}
public SeataFeignRequestInterceptor seataFeignRequestInterceptor() {
return new SeataFeignRequestInterceptor();
}
}

@ -1,69 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.seata.feign;
import java.util.HashMap;
import java.util.Map;
import feign.Client;
import org.springframework.cloud.openfeign.FeignContext;
/**
* @author xiaojing
*/
public class SeataFeignContext extends FeignContext {
private final SeataFeignObjectWrapper seataFeignObjectWrapper;
private final FeignContext delegate;
SeataFeignContext(SeataFeignObjectWrapper seataFeignObjectWrapper,
FeignContext delegate) {
this.seataFeignObjectWrapper = seataFeignObjectWrapper;
this.delegate = delegate;
}
@Override
public <T> T getInstance(String name, Class<T> type) {
T object = this.delegate.getInstance(name, type);
if (object instanceof Client) {
return object;
}
return (T) this.seataFeignObjectWrapper.wrap(object);
}
@Override
public <T> Map<String, T> getInstances(String name, Class<T> type) {
Map<String, T> instances = this.delegate.getInstances(name, type);
if (instances == null) {
return null;
}
Map<String, T> convertedInstances = new HashMap<>();
for (Map.Entry<String, T> entry : instances.entrySet()) {
if (entry.getValue() instanceof Client) {
convertedInstances.put(entry.getKey(), entry.getValue());
}
else {
convertedInstances.put(entry.getKey(),
(T) this.seataFeignObjectWrapper.wrap(entry.getValue()));
}
}
return convertedInstances;
}
}

@ -1,81 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.seata.feign;
import feign.Client;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient;
import org.springframework.cloud.openfeign.ribbon.CachingSpringLoadBalancerFactory;
import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient;
/**
* @author xiaojing
*/
public class SeataFeignObjectWrapper {
private static final Logger LOG = LoggerFactory
.getLogger(SeataFeignObjectWrapper.class);
private final BeanFactory beanFactory;
private CachingSpringLoadBalancerFactory cachingSpringLoadBalancerFactory;
private SpringClientFactory springClientFactory;
SeataFeignObjectWrapper(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
Object wrap(Object bean) {
if (bean instanceof Client && !(bean instanceof SeataFeignClient)) {
if (bean instanceof LoadBalancerFeignClient) {
LoadBalancerFeignClient client = ((LoadBalancerFeignClient) bean);
return new SeataLoadBalancerFeignClient(client.getDelegate(), factory(),
clientFactory(), this);
}
if (bean instanceof FeignBlockingLoadBalancerClient) {
FeignBlockingLoadBalancerClient client = (FeignBlockingLoadBalancerClient) bean;
return new SeataFeignBlockingLoadBalancerClient(client.getDelegate(),
beanFactory.getBean(BlockingLoadBalancerClient.class), this);
}
return new SeataFeignClient(this.beanFactory, (Client) bean);
}
return bean;
}
CachingSpringLoadBalancerFactory factory() {
if (this.cachingSpringLoadBalancerFactory == null) {
this.cachingSpringLoadBalancerFactory = this.beanFactory
.getBean(CachingSpringLoadBalancerFactory.class);
}
return this.cachingSpringLoadBalancerFactory;
}
SpringClientFactory clientFactory() {
if (this.springClientFactory == null) {
this.springClientFactory = this.beanFactory
.getBean(SpringClientFactory.class);
}
return this.springClientFactory;
}
}

@ -16,23 +16,29 @@
package com.alibaba.cloud.seata.feign;
import feign.Feign;
import feign.Retryer;
import feign.hystrix.HystrixFeign;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.BeanFactory;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import io.seata.core.context.RootContext;
import org.springframework.util.StringUtils;
/**
* @author xiaojing
* @author wang.liang
*/
final class SeataHystrixFeignBuilder {
public class SeataFeignRequestInterceptor implements RequestInterceptor {
private SeataHystrixFeignBuilder() {
}
@Override
public void apply(RequestTemplate template) {
String xid = RootContext.getXID();
if (StringUtils.isEmpty(xid)) {
return;
}
static Feign.Builder builder(BeanFactory beanFactory) {
return HystrixFeign.builder().retryer(Retryer.NEVER_RETRY)
.client(new SeataFeignClient(beanFactory));
List<String> seataXid = new ArrayList<>();
seataXid.add(xid);
template.header(RootContext.KEY_XID, xid);
}
}

@ -1,48 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.seata.feign;
import java.io.IOException;
import feign.Client;
import feign.Request;
import feign.Response;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.cloud.openfeign.ribbon.CachingSpringLoadBalancerFactory;
import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient;
/**
* @author xiaojing
* @author yuhuangbin
*/
public class SeataLoadBalancerFeignClient extends LoadBalancerFeignClient {
SeataLoadBalancerFeignClient(Client delegate,
CachingSpringLoadBalancerFactory lbClientFactory,
SpringClientFactory clientFactory,
SeataFeignObjectWrapper seataFeignObjectWrapper) {
super((Client) seataFeignObjectWrapper.wrap(delegate), lbClientFactory,
clientFactory);
}
@Override
public Response execute(Request request, Request.Options options) throws IOException {
return super.execute(request, options);
}
}

@ -1,38 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.seata.feign;
import com.alibaba.cloud.sentinel.feign.SentinelFeign;
import feign.Feign;
import feign.Retryer;
import org.springframework.beans.factory.BeanFactory;
/**
* @author xiaojing
*/
final class SeataSentinelFeignBuilder {
private SeataSentinelFeignBuilder() {
}
static Feign.Builder builder(BeanFactory beanFactory) {
return SentinelFeign.builder().retryer(Retryer.NEVER_RETRY)
.client(new SeataFeignClient(beanFactory));
}
}
Loading…
Cancel
Save