Ensure that BPP dependencies are not created too early

The FeignBeanPostProcessor was causing other things to misbehave
by forcing early instantiation of all its dependencies. One of those
is a @MessageEndpoint when Sleuth Stream is in use, and the annotation
wasn't being processed because the bean was processed too early.
This commit is contained in:
Dave Syer
2016-03-17 11:29:46 +00:00
parent d365fedbc0
commit 35ba7bab95
5 changed files with 51 additions and 32 deletions

View File

@@ -61,7 +61,7 @@ public class TraceAutoConfiguration {
@Bean
@ConditionalOnMissingBean(Tracer.class)
public DefaultTracer traceManager(Sampler sampler, Random random,
public DefaultTracer sleuthTracer(Sampler sampler, Random random,
SpanNamer spanNamer, SpanLogger spanLogger,
SpanReporter spanReporter) {
return new DefaultTracer(sampler, random, spanNamer, spanLogger,

View File

@@ -17,6 +17,7 @@
package org.springframework.cloud.sleuth.instrument.web.client.feign;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.cloud.sleuth.Tracer;
@@ -34,25 +35,33 @@ import feign.codec.Decoder;
*/
final class FeignBeanPostProcessor implements BeanPostProcessor {
private final Tracer tracer;
private Tracer tracer;
private final BeanFactory beanFactory;
FeignBeanPostProcessor(Tracer tracer) {
this.tracer = tracer;
FeignBeanPostProcessor(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof Decoder && !(bean instanceof TraceFeignDecoder)) {
return new TraceFeignDecoder(this.tracer, (Decoder) bean);
return new TraceFeignDecoder(getTracer(), (Decoder) bean);
} else if (bean instanceof Retryer && !(bean instanceof TraceFeignRetryer)) {
return new TraceFeignRetryer(this.tracer, (Retryer) bean);
return new TraceFeignRetryer(getTracer(), (Retryer) bean);
} else if (bean instanceof Client && !(bean instanceof TraceFeignClient)) {
return new TraceFeignClient(this.tracer, (Client) bean);
return new TraceFeignClient(getTracer(), (Client) bean);
}
return bean;
}
private Tracer getTracer() {
if (this.tracer==null) {
this.tracer = this.beanFactory.getBean(Tracer.class);
}
return this.tracer;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {

View File

@@ -19,6 +19,7 @@ package org.springframework.cloud.sleuth.instrument.web.client.feign;
import java.io.IOException;
import java.lang.reflect.Type;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
@@ -49,8 +50,8 @@ import feign.Response;
import feign.codec.Decoder;
/**
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration Auto-configuration}
* enables span information propagation when using Feign.
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
* Auto-configuration} enables span information propagation when using Feign.
*
* @author Marcin Grzejszczak
*
@@ -74,33 +75,44 @@ public class TraceFeignClientAutoConfiguration {
return SleuthFeignBuilder.builder(tracer);
}
@Bean
@ConditionalOnProperty(name = "spring.sleuth.feign.processor.enabled", matchIfMissing = true)
FeignBeanPostProcessor feignBeanPostProcessor(Tracer tracer) {
return new FeignBeanPostProcessor(tracer);
@Configuration
protected static class FeignBeanPostProcessorConfiguration {
@Bean
@ConditionalOnProperty(name = "spring.sleuth.feign.processor.enabled", matchIfMissing = true)
FeignBeanPostProcessor feignBeanPostProcessor(BeanFactory beanFactory) {
return new FeignBeanPostProcessor(beanFactory);
}
}
@Bean
@Primary
Decoder feignDecoder(final Tracer tracer) {
return new TraceFeignDecoder(tracer, new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)) {
@Override
public Object decode(Response response, Type type)
throws IOException, FeignException {
FeignRequestContext feignRequestContext = FeignRequestContext.getInstance();
FeignResponseHeadersHolder feignResponseHeadersHolder =
new FeignResponseHeadersHolder(response.headers());
feignResponseHeadersInjector().inject(feignRequestContext.getCurrentSpan(), feignResponseHeadersHolder);
return super.decode(Response.create(response.status(),
response.reason(), feignResponseHeadersHolder.responseHeaders,
response.body()), type);
}
});
return new TraceFeignDecoder(tracer,
new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)) {
@Override
public Object decode(Response response, Type type)
throws IOException, FeignException {
FeignRequestContext feignRequestContext = FeignRequestContext
.getInstance();
FeignResponseHeadersHolder feignResponseHeadersHolder = new FeignResponseHeadersHolder(
response.headers());
feignResponseHeadersInjector().inject(
feignRequestContext.getCurrentSpan(),
feignResponseHeadersHolder);
return super.decode(
Response.create(response.status(), response.reason(),
feignResponseHeadersHolder.responseHeaders,
response.body()),
type);
}
});
}
/**
* Sleuth {@link feign.RequestInterceptor} that either starts a new Span
* or continues an existing one if a retry takes place.
* Sleuth {@link feign.RequestInterceptor} that either starts a new Span or continues
* an existing one if a retry takes place.
*/
@Bean
public RequestInterceptor traceIdRequestInterceptor(Tracer tracer) {

View File

@@ -18,12 +18,10 @@ package org.springframework.cloud.sleuth.log;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -38,7 +36,7 @@ import org.springframework.context.annotation.Configuration;
* @since 1.0.0
*/
@Configuration
@ConditionalOnBean(Tracer.class)
@ConditionalOnProperty(value="spring.sleuth.enabled", matchIfMissing=true)
public class SleuthLogAutoConfiguration {
@Configuration

View File

@@ -72,7 +72,7 @@ public class SleuthStreamAutoConfiguration {
}
@Bean
public StreamSpanListener sleuthTracer(HostLocator endpointLocator,
public StreamSpanListener sleuthStreamSpanListener(HostLocator endpointLocator,
SpanMetricReporter spanMetricReporter) {
return new StreamSpanListener(endpointLocator, spanMetricReporter);
}