Code optimization for rpc-enhancement module (#526)

pull/528/head
DerekYRC 2 years ago committed by GitHub
parent aa53605159
commit b9415449dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -19,3 +19,4 @@
- [BeanFactoryUtils returns all beans including beans defined in ancestor bean factories](https://github.com/Tencent/spring-cloud-tencent/pull/517)
- [fix:add spring-cloud-starter-bootstrap dependency for example](https://github.com/Tencent/spring-cloud-tencent/pull/521)
- [Feature: Add router actuate endpoint](https://github.com/Tencent/spring-cloud-tencent/pull/523)
- [Code optimization for rpc-enhancement module](https://github.com/Tencent/spring-cloud-tencent/pull/526)

@ -20,11 +20,12 @@ package com.tencent.cloud.rpc.enhancement.config;
import java.util.List;
import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration;
import com.tencent.cloud.rpc.enhancement.feign.DefaultEnhancedFeignPluginRunner;
import com.tencent.cloud.rpc.enhancement.feign.EnhancedFeignBeanPostProcessor;
import com.tencent.cloud.rpc.enhancement.feign.EnhancedFeignPluginRunner;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPlugin;
import com.tencent.cloud.rpc.enhancement.feign.plugin.reporter.ExceptionPolarisReporter;
import com.tencent.cloud.rpc.enhancement.feign.plugin.reporter.SuccessPolarisReporter;
import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateModifier;
import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateReporter;
import com.tencent.cloud.rpc.enhancement.resttemplate.PolarisResponseErrorHandler;
import com.tencent.polaris.api.core.ConsumerAPI;
@ -35,13 +36,11 @@ import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.loadbalancer.RestTemplateCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.web.client.RestTemplate;
import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE;
/**
* Auto Configuration for Polaris {@link feign.Feign} OR {@link RestTemplate} which can automatically bring in the call
* results for reporting.
@ -66,10 +65,14 @@ public class RpcEnhancementAutoConfiguration {
protected static class PolarisFeignClientAutoConfiguration {
@Bean
@Order(HIGHEST_PRECEDENCE)
public EnhancedFeignBeanPostProcessor polarisFeignBeanPostProcessor(
public EnhancedFeignPluginRunner enhancedFeignPluginRunner(
@Autowired(required = false) List<EnhancedFeignPlugin> enhancedFeignPlugins) {
return new EnhancedFeignBeanPostProcessor(enhancedFeignPlugins);
return new DefaultEnhancedFeignPluginRunner(enhancedFeignPlugins);
}
@Bean
public EnhancedFeignBeanPostProcessor polarisFeignBeanPostProcessor(EnhancedFeignPluginRunner pluginRunner) {
return new EnhancedFeignBeanPostProcessor(pluginRunner);
}
@Configuration
@ -105,9 +108,8 @@ public class RpcEnhancementAutoConfiguration {
}
@Bean
public EnhancedRestTemplateModifier polarisRestTemplateBeanPostProcessor(
EnhancedRestTemplateReporter restTemplateResponseErrorHandler) {
return new EnhancedRestTemplateModifier(restTemplateResponseErrorHandler);
public RestTemplateCustomizer setErrorHandlerCustomizer(EnhancedRestTemplateReporter reporter) {
return restTemplate -> restTemplate.setErrorHandler(reporter);
}
}
}

@ -0,0 +1,66 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.rpc.enhancement.feign;
import java.util.Comparator;
import java.util.List;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignContext;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPlugin;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType;
import org.springframework.util.CollectionUtils;
/**
* Default plugin runner.
*
* @author Derek Yi 2022-08-16
*/
public class DefaultEnhancedFeignPluginRunner implements EnhancedFeignPluginRunner {
private Multimap<String, EnhancedFeignPlugin> pluginMap = ArrayListMultimap.create();
public DefaultEnhancedFeignPluginRunner(List<EnhancedFeignPlugin> enhancedFeignPlugins) {
if (!CollectionUtils.isEmpty(enhancedFeignPlugins)) {
enhancedFeignPlugins.stream()
.sorted(Comparator.comparing(EnhancedFeignPlugin::getOrder))
.forEach(plugin -> pluginMap.put(plugin.getType().name(), plugin));
}
}
/**
* run the plugin.
*
* @param pluginType type of plugin
* @param context context in enhanced feign client.
*/
@Override
public void run(EnhancedFeignPluginType pluginType, EnhancedFeignContext context) {
for (EnhancedFeignPlugin plugin : pluginMap.get(pluginType.name())) {
try {
plugin.run(context);
}
catch (Throwable throwable) {
plugin.handlerThrowable(context, throwable);
}
}
}
}

@ -17,9 +17,6 @@
package com.tencent.cloud.rpc.enhancement.feign;
import java.util.List;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPlugin;
import feign.Client;
import org.springframework.beans.BeansException;
@ -38,12 +35,12 @@ import org.springframework.cloud.openfeign.loadbalancer.RetryableFeignBlockingLo
*/
public class EnhancedFeignBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
private final List<EnhancedFeignPlugin> enhancedFeignPlugins;
private EnhancedFeignPluginRunner pluginRunner;
private BeanFactory factory;
public EnhancedFeignBeanPostProcessor(List<EnhancedFeignPlugin> enhancedFeignPlugins) {
this.enhancedFeignPlugins = enhancedFeignPlugins;
public EnhancedFeignBeanPostProcessor(EnhancedFeignPluginRunner pluginRunner) {
this.pluginRunner = pluginRunner;
}
@Override
@ -79,7 +76,7 @@ public class EnhancedFeignBeanPostProcessor implements BeanPostProcessor, BeanFa
}
private EnhancedFeignClient createPolarisFeignClient(Client delegate) {
return new EnhancedFeignClient(delegate, enhancedFeignPlugins);
return new EnhancedFeignClient(delegate, pluginRunner);
}
@Override

@ -18,21 +18,17 @@
package com.tencent.cloud.rpc.enhancement.feign;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignContext;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPlugin;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType;
import feign.Client;
import feign.Request;
import feign.Request.Options;
import feign.Response;
import org.springframework.util.CollectionUtils;
import static com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType.EXCEPTION;
import static com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType.FINALLY;
import static com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType.POST;
import static com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType.PRE;
import static feign.Util.checkNotNull;
/**
@ -44,43 +40,11 @@ public class EnhancedFeignClient implements Client {
private final Client delegate;
private List<EnhancedFeignPlugin> preEnhancedFeignPlugins;
private List<EnhancedFeignPlugin> postEnhancedFeignPlugins;
private List<EnhancedFeignPlugin> exceptionEnhancedFeignPlugins;
private EnhancedFeignPluginRunner pluginRunner;
private List<EnhancedFeignPlugin> finallyEnhancedFeignPlugins;
public EnhancedFeignClient(Client target, List<EnhancedFeignPlugin> enhancedFeignPlugins) {
public EnhancedFeignClient(Client target, EnhancedFeignPluginRunner pluginRunner) {
this.delegate = checkNotNull(target, "target");
// Init the EnhancedFeignPlugins list.
this.preEnhancedFeignPlugins = new ArrayList<>();
this.postEnhancedFeignPlugins = new ArrayList<>();
this.exceptionEnhancedFeignPlugins = new ArrayList<>();
this.finallyEnhancedFeignPlugins = new ArrayList<>();
if (!CollectionUtils.isEmpty(enhancedFeignPlugins)) {
for (EnhancedFeignPlugin feignPlugin : enhancedFeignPlugins) {
if (feignPlugin.getType().equals(EnhancedFeignPluginType.PRE)) {
this.preEnhancedFeignPlugins.add(feignPlugin);
}
else if (feignPlugin.getType().equals(EnhancedFeignPluginType.POST)) {
this.postEnhancedFeignPlugins.add(feignPlugin);
}
else if (feignPlugin.getType().equals(EnhancedFeignPluginType.EXCEPTION)) {
this.exceptionEnhancedFeignPlugins.add(feignPlugin);
}
else if (feignPlugin.getType().equals(EnhancedFeignPluginType.FINALLY)) {
this.finallyEnhancedFeignPlugins.add(feignPlugin);
}
}
}
// Set the ordered enhanced feign plugins.
this.preEnhancedFeignPlugins = getSortedEnhancedFeignPlugin(this.preEnhancedFeignPlugins);
this.postEnhancedFeignPlugins = getSortedEnhancedFeignPlugin(this.postEnhancedFeignPlugins);
this.exceptionEnhancedFeignPlugins = getSortedEnhancedFeignPlugin(this.exceptionEnhancedFeignPlugins);
this.finallyEnhancedFeignPlugins = getSortedEnhancedFeignPlugin(this.finallyEnhancedFeignPlugins);
this.pluginRunner = pluginRunner;
}
@Override
@ -90,64 +54,24 @@ public class EnhancedFeignClient implements Client {
enhancedFeignContext.setOptions(options);
// Run pre enhanced feign plugins.
for (EnhancedFeignPlugin plugin : preEnhancedFeignPlugins) {
try {
plugin.run(enhancedFeignContext);
}
catch (Throwable throwable) {
plugin.handlerThrowable(enhancedFeignContext, throwable);
}
}
pluginRunner.run(PRE, enhancedFeignContext);
try {
Response response = delegate.execute(request, options);
enhancedFeignContext.setResponse(response);
// Run post enhanced feign plugins.
for (EnhancedFeignPlugin plugin : postEnhancedFeignPlugins) {
try {
plugin.run(enhancedFeignContext);
}
catch (Throwable throwable) {
plugin.handlerThrowable(enhancedFeignContext, throwable);
}
}
pluginRunner.run(POST, enhancedFeignContext);
return response;
}
catch (IOException origin) {
enhancedFeignContext.setException(origin);
// Run exception enhanced feign plugins.
for (EnhancedFeignPlugin plugin : exceptionEnhancedFeignPlugins) {
try {
plugin.run(enhancedFeignContext);
}
catch (Throwable throwable) {
plugin.handlerThrowable(enhancedFeignContext, throwable);
}
}
pluginRunner.run(EXCEPTION, enhancedFeignContext);
throw origin;
}
finally {
// Run finally enhanced feign plugins.
for (EnhancedFeignPlugin plugin : finallyEnhancedFeignPlugins) {
try {
plugin.run(enhancedFeignContext);
}
catch (Throwable throwable) {
plugin.handlerThrowable(enhancedFeignContext, throwable);
}
}
pluginRunner.run(FINALLY, enhancedFeignContext);
}
}
/**
* Ascending, which means the lower order number, the earlier executing enhanced feign plugin.
*
* @return sorted feign pre plugin list
*/
private List<EnhancedFeignPlugin> getSortedEnhancedFeignPlugin(List<EnhancedFeignPlugin> preEnhancedFeignPlugins) {
return new ArrayList<>(preEnhancedFeignPlugins)
.stream()
.sorted(Comparator.comparing(EnhancedFeignPlugin::getOrder))
.collect(Collectors.toList());
}
}

@ -0,0 +1,38 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.rpc.enhancement.feign;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignContext;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType;
/**
* Plugin runner.
*
* @author Derek Yi 2022-08-16
*/
public interface EnhancedFeignPluginRunner {
/**
* run the plugin.
*
* @param pluginType type of plugin
* @param context context in enhanced feign client.
*/
void run(EnhancedFeignPluginType pluginType, EnhancedFeignContext context);
}

@ -20,7 +20,7 @@ package com.tencent.cloud.rpc.enhancement.feign.plugin;
import org.springframework.core.Ordered;
/**
* Pre plugin used by EnhancedFeignClient.
* Plugin used by EnhancedFeignClient.
*
* @author Haotian Zhang
*/

@ -34,7 +34,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
/**
* Polaris reporter when feign call is successful.
* Polaris reporter when feign call fails.
*
* @author Haotian Zhang
*/

@ -1,65 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.rpc.enhancement.resttemplate;
import java.util.Map;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;
/**
* Autoconfiguration RestTemplate, Find the RestTemplate bean annotated with {@link LoadBalanced},
* then replace {@link org.springframework.web.client.ResponseErrorHandler}
* with {@link EnhancedRestTemplateReporter} .
*
* @author wh 2022/6/21
*/
public class EnhancedRestTemplateModifier implements ApplicationContextAware, SmartInitializingSingleton {
private final EnhancedRestTemplateReporter enhancedRestTemplateReporter;
private ApplicationContext applicationContext;
public EnhancedRestTemplateModifier(EnhancedRestTemplateReporter enhancedRestTemplateReporter) {
this.enhancedRestTemplateReporter = enhancedRestTemplateReporter;
}
@Override
public void afterSingletonsInstantiated() {
Map<String, Object> beans = this.applicationContext.getBeansWithAnnotation(LoadBalanced.class);
if (!ObjectUtils.isEmpty(beans)) {
beans.forEach(this::initRestTemplate);
}
}
private void initRestTemplate(String beanName, Object bean) {
if (bean instanceof RestTemplate) {
RestTemplate restTemplate = (RestTemplate) bean;
restTemplate.setErrorHandler(enhancedRestTemplateReporter);
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}

@ -20,9 +20,9 @@ package com.tencent.cloud.rpc.enhancement.stat.config;
import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.env.Environment;
/**
@ -32,7 +32,7 @@ import org.springframework.core.env.Environment;
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnPolarisEnabled
@Import({PolarisStatProperties.class})
@EnableConfigurationProperties(PolarisStatProperties.class)
public class PolarisStatPropertiesAutoConfiguration {
@Bean

@ -17,11 +17,14 @@
package com.tencent.cloud.rpc.enhancement.config;
import java.io.IOException;
import java.net.URI;
import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration;
import com.tencent.cloud.rpc.enhancement.feign.EnhancedFeignBeanPostProcessor;
import com.tencent.cloud.rpc.enhancement.feign.EnhancedFeignPluginRunner;
import com.tencent.cloud.rpc.enhancement.feign.plugin.reporter.ExceptionPolarisReporter;
import com.tencent.cloud.rpc.enhancement.feign.plugin.reporter.SuccessPolarisReporter;
import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateModifier;
import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateReporter;
import com.tencent.polaris.api.core.ConsumerAPI;
import org.junit.Test;
@ -29,6 +32,13 @@ import org.junit.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerRequest;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.openfeign.loadbalancer.FeignLoadBalancerAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@ -46,18 +56,23 @@ public class RpcEnhancementAutoConfigurationTest {
.withConfiguration(AutoConfigurations.of(
PolarisContextAutoConfiguration.class,
RpcEnhancementAutoConfiguration.class,
PolarisRestTemplateAutoConfigurationTester.class))
PolarisRestTemplateAutoConfigurationTester.class,
LoadBalancerAutoConfiguration.class,
FeignLoadBalancerAutoConfiguration.class))
.withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true");
@Test
public void testDefaultInitialization() {
this.contextRunner.run(context -> {
assertThat(context).hasSingleBean(ConsumerAPI.class);
assertThat(context).hasSingleBean(EnhancedFeignPluginRunner.class);
assertThat(context).hasSingleBean(EnhancedFeignBeanPostProcessor.class);
assertThat(context).hasSingleBean(SuccessPolarisReporter.class);
assertThat(context).hasSingleBean(ExceptionPolarisReporter.class);
assertThat(context).hasSingleBean(EnhancedRestTemplateModifier.class);
assertThat(context).hasSingleBean(EnhancedRestTemplateReporter.class);
assertThat(context).hasSingleBean(RestTemplate.class);
RestTemplate restTemplate = context.getBean(RestTemplate.class);
assertThat(restTemplate.getErrorHandler() instanceof EnhancedRestTemplateReporter).isTrue();
});
}
@ -66,8 +81,40 @@ public class RpcEnhancementAutoConfigurationTest {
static class PolarisRestTemplateAutoConfigurationTester {
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
LoadBalancerClient loadBalancerClient() {
return new LoadBalancerClient() {
@Override
public ServiceInstance choose(String serviceId) {
return null;
}
@Override
public <T> ServiceInstance choose(String serviceId, Request<T> request) {
return null;
}
@Override
public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
return null;
}
@Override
public <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException {
return null;
}
@Override
public URI reconstructURI(ServiceInstance instance, URI original) {
return null;
}
};
}
}
}

@ -74,7 +74,7 @@ public class EnhancedFeignClientTest {
List<EnhancedFeignPlugin> enhancedFeignPlugins = getMockEnhancedFeignPlugins();
try {
new EnhancedFeignClient(mock(Client.class), enhancedFeignPlugins);
new EnhancedFeignClient(mock(Client.class), new DefaultEnhancedFeignPluginRunner(enhancedFeignPlugins));
}
catch (Throwable e) {
fail("Exception encountered.", e);
@ -103,7 +103,7 @@ public class EnhancedFeignClientTest {
RequestTemplate requestTemplate = new RequestTemplate();
requestTemplate.feignTarget(target);
EnhancedFeignClient polarisFeignClient = new EnhancedFeignClient(delegate, getMockEnhancedFeignPlugins());
EnhancedFeignClient polarisFeignClient = new EnhancedFeignClient(delegate, new DefaultEnhancedFeignPluginRunner(getMockEnhancedFeignPlugins()));
// 200
Response response = polarisFeignClient.execute(Request.create(Request.HttpMethod.GET, "http://localhost:8080/test",

Loading…
Cancel
Save