Fixes proxy issues; fixes gh-932

This commit is contained in:
Marcin Grzejszczak
2018-02-28 15:08:12 +01:00
committed by Marcin Grzejszczak
parent 51e66dba22
commit 98d6572ebc
17 changed files with 150 additions and 83 deletions

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.cloud.sleuth.annotation;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -24,6 +25,7 @@ import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
/**
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
@@ -36,6 +38,7 @@ import org.springframework.context.annotation.Configuration;
* @since 1.2.0
*/
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@ConditionalOnBean(Tracer.class)
@ConditionalOnProperty(name = "spring.sleuth.annotation.enabled", matchIfMissing = true)
@AutoConfigureAfter(TraceAutoConfiguration.class)
@@ -61,8 +64,8 @@ public class SleuthAnnotationAutoConfiguration {
}
@Bean
SleuthAdvisorConfig sleuthAdvisorConfig() {
@Role(BeanDefinition.ROLE_INFRASTRUCTURE) SleuthAdvisorConfig sleuthAdvisorConfig() {
return new SleuthAdvisorConfig();
}
}

View File

@@ -20,6 +20,7 @@ import java.util.concurrent.Executor;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -28,6 +29,7 @@ import org.springframework.cloud.sleuth.TraceKeys;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.AsyncConfigurerSupport;
@@ -49,11 +51,10 @@ import org.springframework.scheduling.annotation.AsyncConfigurerSupport;
@AutoConfigureAfter(AsyncCustomAutoConfiguration.class)
public class AsyncDefaultAutoConfiguration {
@Autowired private BeanFactory beanFactory;
@Configuration
@ConditionalOnMissingBean(AsyncConfigurer.class)
@ConditionalOnProperty(value = "spring.sleuth.async.configurer.enabled", matchIfMissing = true)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
static class DefaultAsyncConfigurerSupport extends AsyncConfigurerSupport {
@Autowired private BeanFactory beanFactory;
@@ -64,14 +65,16 @@ public class AsyncDefaultAutoConfiguration {
}
}
@Autowired private BeanFactory beanFactory;
@Bean
public TraceAsyncAspect traceAsyncAspect(Tracer tracer, TraceKeys traceKeys) {
return new TraceAsyncAspect(tracer, traceKeys, this.beanFactory);
}
@Bean
public ExecutorBeanPostProcessor executorBeanPostProcessor() {
return new ExecutorBeanPostProcessor(this.beanFactory);
public static ExecutorBeanPostProcessor executorBeanPostProcessor(BeanFactory beanFactory) {
return new ExecutorBeanPostProcessor(beanFactory);
}
}

View File

@@ -16,6 +16,7 @@
package org.springframework.cloud.sleuth.instrument.web;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@@ -30,6 +31,7 @@ import org.springframework.cloud.sleuth.Tracer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Role;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import static javax.servlet.DispatcherType.ASYNC;
@@ -49,6 +51,7 @@ import static javax.servlet.DispatcherType.REQUEST;
* @since 1.0.0
*/
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@ConditionalOnProperty(value = "spring.sleuth.web.enabled", matchIfMissing = true)
@ConditionalOnWebApplication
@ConditionalOnBean(Tracer.class)

View File

@@ -16,6 +16,7 @@
package org.springframework.cloud.sleuth.instrument.web.client;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -37,7 +38,10 @@ import org.springframework.cloud.sleuth.instrument.web.TraceWebAutoConfiguration
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.web.client.RestTemplate;
@@ -77,9 +81,8 @@ public class TraceWebClientAutoConfiguration {
return new TraceRestTemplateCustomizer(this.traceRestTemplateInterceptor);
}
@Bean
TraceRestTemplateBPP traceRestTemplateBPP(BeanFactory beanFactory) {
return new TraceRestTemplateBPP(beanFactory);
@Bean static TraceRestTemplateBeanPostProcessor traceRestTemplateBPP(BeanFactory beanFactory) {
return new TraceRestTemplateBeanPostProcessor(beanFactory);
}
}
@@ -87,24 +90,21 @@ public class TraceWebClientAutoConfiguration {
@ConditionalOnClass({ UserInfoRestTemplateCustomizer.class, OAuth2RestTemplate.class })
protected static class TraceOAuthConfiguration {
@Autowired BeanFactory beanFactory;
@Bean
UserInfoRestTemplateCustomizerBPP userInfoRestTemplateCustomizerBeanPostProcessor() {
return new UserInfoRestTemplateCustomizerBPP(this.beanFactory);
@Bean static UserInfoRestTemplateCustomizerBeanPostProcessor userInfoRestTemplateCustomizerBeanPostProcessor(BeanFactory beanFactory) {
return new UserInfoRestTemplateCustomizerBeanPostProcessor(beanFactory);
}
@Bean
@ConditionalOnMissingBean
UserInfoRestTemplateCustomizer traceUserInfoRestTemplateCustomizer() {
return new TraceUserInfoRestTemplateCustomizer(this.beanFactory);
UserInfoRestTemplateCustomizer traceUserInfoRestTemplateCustomizer(BeanFactory beanFactory) {
return new TraceUserInfoRestTemplateCustomizer(beanFactory);
}
private static class UserInfoRestTemplateCustomizerBPP implements BeanPostProcessor {
private static class UserInfoRestTemplateCustomizerBeanPostProcessor implements BeanPostProcessor {
private final BeanFactory beanFactory;
UserInfoRestTemplateCustomizerBPP(BeanFactory beanFactory) {
UserInfoRestTemplateCustomizerBeanPostProcessor(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@@ -129,9 +129,9 @@ public class TraceWebClientAutoConfiguration {
}
class RestTemplateInterceptorInjector {
private final TraceRestTemplateInterceptor interceptor;
private final ClientHttpRequestInterceptor interceptor;
RestTemplateInterceptorInjector(TraceRestTemplateInterceptor interceptor) {
RestTemplateInterceptorInjector(ClientHttpRequestInterceptor interceptor) {
this.interceptor = interceptor;
}
@@ -170,12 +170,12 @@ class TraceRestTemplateCustomizer implements RestTemplateCustomizer {
}
}
class TraceRestTemplateBPP implements BeanPostProcessor {
class TraceRestTemplateBeanPostProcessor implements BeanPostProcessor {
private final BeanFactory beanFactory;
private TraceRestTemplateInterceptor interceptor;
TraceRestTemplateBPP(BeanFactory beanFactory) {
TraceRestTemplateBeanPostProcessor(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@@ -193,6 +193,26 @@ class TraceRestTemplateBPP implements BeanPostProcessor {
return bean;
}
private ClientHttpRequestInterceptor interceptor() {
return new LazyTracingClientHttpRequestInterceptor(this.beanFactory);
}
}
class LazyTracingClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
private final BeanFactory beanFactory;
private TraceRestTemplateInterceptor interceptor;
public LazyTracingClientHttpRequestInterceptor(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override public ClientHttpResponse intercept(HttpRequest request, byte[] body,
ClientHttpRequestExecution execution) throws IOException {
return interceptor().intercept(request, body, execution);
}
private TraceRestTemplateInterceptor interceptor() {
if (this.interceptor == null) {
this.interceptor = this.beanFactory.getBean(TraceRestTemplateInterceptor.class);

View File

@@ -31,7 +31,6 @@ import org.springframework.cloud.netflix.feign.FeignContext;
final class FeignContextBeanPostProcessor implements BeanPostProcessor {
private final BeanFactory beanFactory;
private TraceFeignObjectWrapper traceFeignObjectWrapper;
FeignContextBeanPostProcessor(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
@@ -40,22 +39,19 @@ final class FeignContextBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof FeignContext && !(bean instanceof TraceFeignContext)) {
return new TraceFeignContext(getTraceFeignObjectWrapper(), (FeignContext) bean);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof FeignContext && !(bean instanceof TraceFeignContext)) {
return new TraceFeignContext(traceFeignObjectWrapper(), (FeignContext) bean);
}
return bean;
}
private TraceFeignObjectWrapper getTraceFeignObjectWrapper() {
if (this.traceFeignObjectWrapper == null) {
this.traceFeignObjectWrapper = this.beanFactory.getBean(TraceFeignObjectWrapper.class);
}
return this.traceFeignObjectWrapper;
private TraceFeignObjectWrapper traceFeignObjectWrapper() {
return new TraceFeignObjectWrapper(this.beanFactory);
}
}

View File

@@ -0,0 +1,44 @@
/*
* 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
*
* http://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 org.springframework.cloud.sleuth.instrument.web.client.feign;
import java.io.IOException;
import feign.Client;
import feign.Request;
import feign.Response;
import org.springframework.beans.factory.BeanFactory;
class LazyClient implements Client {
private final BeanFactory beanFactory;
private final Client delegate;
LazyClient(BeanFactory beanFactory, Client delegate) {
this.beanFactory = beanFactory;
this.delegate = delegate;
}
@Override public Response execute(Request request, Request.Options options)
throws IOException {
return ((Client) wrapper().wrap(this.delegate)).execute(request, options);
}
private TraceFeignObjectWrapper wrapper() {
return new TraceFeignObjectWrapper(this.beanFactory);
}
}

View File

@@ -16,12 +16,12 @@
package org.springframework.cloud.sleuth.instrument.web.client.feign;
import feign.Client;
import feign.okhttp.OkHttpClient;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanPostProcessor;
import feign.okhttp.OkHttpClient;
/**
* Post processor that wraps takes care of the OkHttp Feign Client instrumentation
*
@@ -32,7 +32,6 @@ import feign.okhttp.OkHttpClient;
final class OkHttpFeignClientBeanPostProcessor implements BeanPostProcessor {
private final BeanFactory beanFactory;
private TraceFeignObjectWrapper traceFeignObjectWrapper;
OkHttpFeignClientBeanPostProcessor(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
@@ -41,8 +40,8 @@ final class OkHttpFeignClientBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof OkHttpClient) {
return getTraceFeignObjectWrapper().wrap(bean);
if (bean instanceof OkHttpClient && !(bean instanceof LazyClient)) {
return new LazyClient(this.beanFactory, (Client) bean);
}
return bean;
}
@@ -52,11 +51,4 @@ final class OkHttpFeignClientBeanPostProcessor implements BeanPostProcessor {
throws BeansException {
return bean;
}
private TraceFeignObjectWrapper getTraceFeignObjectWrapper() {
if (this.traceFeignObjectWrapper == null) {
this.traceFeignObjectWrapper = this.beanFactory.getBean(TraceFeignObjectWrapper.class);
}
return this.traceFeignObjectWrapper;
}
}
}

View File

@@ -43,7 +43,7 @@ final class SleuthFeignBuilder {
private static Client client(BeanFactory beanFactory) {
try {
Client client = beanFactory.getBean(Client.class);
return (Client) new TraceFeignObjectWrapper(beanFactory).wrap(client);
return new LazyClient(beanFactory, client);
} catch (BeansException e) {
return new TraceFeignClient(beanFactory);
}

View File

@@ -45,7 +45,7 @@ final class SleuthHystrixFeignBuilder {
private static Client client(BeanFactory beanFactory) {
try {
Client client = beanFactory.getBean(Client.class);
return (Client) new TraceFeignObjectWrapper(beanFactory).wrap(client);
return new LazyClient(beanFactory, client);
} catch (BeansException e) {
return new TraceFeignClient(beanFactory);
}

View File

@@ -70,8 +70,7 @@ public class TraceFeignClientAutoConfiguration {
@ConditionalOnProperty(name = "spring.sleuth.feign.processor.enabled", matchIfMissing = true)
protected static class FeignBeanPostProcessorConfiguration {
@Bean
FeignContextBeanPostProcessor feignContextBeanPostProcessor(BeanFactory beanFactory) {
@Bean static FeignContextBeanPostProcessor feignContextBeanPostProcessor(BeanFactory beanFactory) {
return new FeignContextBeanPostProcessor(beanFactory);
}
}
@@ -80,8 +79,7 @@ public class TraceFeignClientAutoConfiguration {
@ConditionalOnClass(OkHttpClient.class)
protected static class OkHttpClientFeignBeanPostProcessorConfiguration {
@Bean
OkHttpFeignClientBeanPostProcessor okHttpFeignClientBeanPostProcessor(BeanFactory beanFactory) {
@Bean static OkHttpFeignClientBeanPostProcessor okHttpFeignClientBeanPostProcessor(BeanFactory beanFactory) {
return new OkHttpFeignClientBeanPostProcessor(beanFactory);
}
}

View File

@@ -16,6 +16,8 @@
package org.springframework.cloud.sleuth.instrument.zuul;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.cloud.netflix.zuul.filters.route.RibbonCommand;
import org.springframework.cloud.netflix.zuul.filters.route.RibbonCommandContext;
import org.springframework.cloud.netflix.zuul.filters.route.RibbonCommandFactory;
@@ -30,24 +32,39 @@ import org.springframework.cloud.sleuth.instrument.web.HttpTraceKeysInjector;
* @author Marcin Grzejszczak
* @since 1.1.0
*/
class TraceRibbonCommandFactory implements RibbonCommandFactory {
class TraceRibbonCommandFactory implements RibbonCommandFactory,
SmartInitializingSingleton {
private Tracer tracer;
private HttpTraceKeysInjector httpTraceKeysInjector;
private final RibbonCommandFactory delegate;
private final Tracer tracer;
private final HttpTraceKeysInjector httpTraceKeysInjector;
private final BeanFactory beanFactory;
public TraceRibbonCommandFactory(RibbonCommandFactory delegate,
Tracer tracer, HttpTraceKeysInjector httpTraceKeysInjector) {
TraceRibbonCommandFactory(RibbonCommandFactory delegate, BeanFactory beanFactory) {
this.beanFactory = beanFactory;
this.delegate = delegate;
this.tracer = tracer;
this.httpTraceKeysInjector = httpTraceKeysInjector;
}
private void initialize() {
if (this.tracer == null) {
this.tracer = this.beanFactory.getBean(Tracer.class);
}
if (this.httpTraceKeysInjector == null) {
this.httpTraceKeysInjector = this.beanFactory.getBean(HttpTraceKeysInjector.class);
}
}
@Override
public RibbonCommand create(RibbonCommandContext context) {
// just in case - everything should be already initialized
initialize();
RibbonCommand ribbonCommand = this.delegate.create(context);
Span span = this.tracer.getCurrentSpan();
this.httpTraceKeysInjector.addRequestTags(span, context.uri(), context.getMethod());
return ribbonCommand;
}
@Override public void afterSingletonsInstantiated() {
initialize();
}
}

View File

@@ -20,8 +20,6 @@ import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.cloud.netflix.zuul.filters.route.RibbonCommandFactory;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.instrument.web.HttpTraceKeysInjector;
/**
* Post processor that wraps a {@link org.springframework.cloud.netflix.zuul.filters.route.RibbonCommandFactory}
@@ -34,8 +32,6 @@ import org.springframework.cloud.sleuth.instrument.web.HttpTraceKeysInjector;
final class TraceRibbonCommandFactoryBeanPostProcessor implements BeanPostProcessor {
private final BeanFactory beanFactory;
private Tracer tracer;
private HttpTraceKeysInjector httpTraceKeysInjector;
TraceRibbonCommandFactoryBeanPostProcessor(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
@@ -44,8 +40,9 @@ final class TraceRibbonCommandFactoryBeanPostProcessor implements BeanPostProces
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof RibbonCommandFactory) {
return new TraceRibbonCommandFactory((RibbonCommandFactory) bean, getTracer(), getHttpTraceKeysInjector());
if (bean instanceof RibbonCommandFactory
&& !(bean instanceof TraceRibbonCommandFactory)) {
return new TraceRibbonCommandFactory((RibbonCommandFactory) bean, this.beanFactory);
}
return bean;
}
@@ -55,18 +52,4 @@ final class TraceRibbonCommandFactoryBeanPostProcessor implements BeanPostProces
throws BeansException {
return bean;
}
Tracer getTracer() {
if (this.tracer == null) {
this.tracer = this.beanFactory.getBean(Tracer.class);
}
return this.tracer;
}
HttpTraceKeysInjector getHttpTraceKeysInjector() {
if (this.httpTraceKeysInjector == null) {
this.httpTraceKeysInjector = this.beanFactory.getBean(HttpTraceKeysInjector.class);
}
return this.httpTraceKeysInjector;
}
}

View File

@@ -68,7 +68,7 @@ public class TraceZuulAutoConfiguration {
}
@Bean
public TraceRibbonCommandFactoryBeanPostProcessor traceRibbonCommandFactoryBeanPostProcessor(BeanFactory beanFactory) {
public static TraceRibbonCommandFactoryBeanPostProcessor traceRibbonCommandFactoryBeanPostProcessor(BeanFactory beanFactory) {
return new TraceRibbonCommandFactoryBeanPostProcessor(beanFactory);
}
@@ -91,7 +91,7 @@ public class TraceZuulAutoConfiguration {
}
@Bean
public TraceZuulHandlerMappingBeanPostProcessor traceHandlerMappingBeanPostProcessor(BeanFactory beanFactory) {
public static TraceZuulHandlerMappingBeanPostProcessor traceHandlerMappingBeanPostProcessor(BeanFactory beanFactory) {
return new TraceZuulHandlerMappingBeanPostProcessor(beanFactory);
}

View File

@@ -58,7 +58,6 @@ public class GH846Test {
}
}
static class MyBean {
@Autowired
private RestTemplate restTemplate;

View File

@@ -71,7 +71,8 @@ public class TraceWebClientAutoConfigurationTests {
int myInterceptorIndex = -1;
int mySecondInterceptorIndex = -1;
for (int i = 0; i < interceptors.size(); i++) {
if (interceptors.get(i) instanceof TraceRestTemplateInterceptor) {
if (interceptors.get(i) instanceof TraceRestTemplateInterceptor ||
interceptors.get(i) instanceof LazyTracingClientHttpRequestInterceptor) {
traceInterceptorIndex = i;
} else if (interceptors.get(i) instanceof MyClientHttpRequestInterceptor) {
myInterceptorIndex = i;

View File

@@ -24,6 +24,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.cloud.netflix.zuul.filters.route.RibbonCommandContext;
import org.springframework.cloud.netflix.zuul.filters.route.RibbonCommandFactory;
@@ -51,6 +52,7 @@ public class TraceRibbonCommandFactoryTest {
@Mock Tracer tracer;
@Mock SpringClientFactory springClientFactory;
@Mock BeanFactory beanFactory;
HttpTraceKeysInjector httpTraceKeysInjector;
@Mock RibbonCommandFactory ribbonCommandFactory;
TraceRibbonCommandFactory traceRibbonCommandFactory;
@@ -62,12 +64,15 @@ public class TraceRibbonCommandFactoryTest {
public void setup() {
this.httpTraceKeysInjector = new HttpTraceKeysInjector(this.tracer, new TraceKeys());
this.traceRibbonCommandFactory = new TraceRibbonCommandFactory(
this.ribbonCommandFactory, this.tracer,
httpTraceKeysInjector);
this.ribbonCommandFactory, this.beanFactory);
given(this.springClientFactory.getClient(anyString(), any(Class.class)))
.willReturn(new RestClient());
given(this.tracer.getCurrentSpan()).willReturn(span);
given(this.tracer.isTracing()).willReturn(true);
given(this.beanFactory.getBean(Tracer.class))
.willReturn(this.tracer);
given(this.beanFactory.getBean(HttpTraceKeysInjector.class))
.willReturn(this.httpTraceKeysInjector);
}
@After