Sleuth обертывает ScheduledExecutorService как LazyTraceExecutor

Я определил bean-компонент ScheduledExecutorService в моем приложении загрузки Spring с поддержкой Sleuth. Когда я получаю этот bean-компонент от сыщика applicationContext, который обернул его с помощью LazyTraceExecutorService, это вызовет исключение BeanNotOfRequiredTypeException.

@SpringBootTest(classes = { Config.class })
@RunWith(SpringRunner.class)
public class SleuthTest {
    @Autowired
    private ApplicationContext applicationContext;

    @Test
    public void testScheduler() {
        // this throws the BeanNotOfRequiredTypeException
        applicationContext.getBean("executorService", ScheduledExecutorService.class);
    }
}

@Configuration
@EnableAutoConfiguration
class Config {
    @Bean
    public ScheduledExecutorService executorService() {
        // Sleuth will wrap this with LazyTraceExecutor, while I would expect a TraceableScheduledExecutorService
        return new ScheduledThreadPoolExecutor(1);
    }
}

Я что-то не так делаю или это баг?

org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'executorService' is expected to be of type 'java.util.concurrent.ScheduledExecutorService' but was actually of type 'org.springframework.cloud.sleuth.instrument.async.LazyTraceExecutor'

    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:378)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1087)
    at com.esaturnus.demotool.SleuthTest.testScheduler(SleuthTest.java:36)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:119)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)

person Hans    schedule 16.01.2017    source источник


Ответы (2)


Я думаю, что это дубликат исключения BeanNotOfRequiredTypeException, когда используя spring-statemachine и spring cloud slueth . Вы пробовали последние релизные версии?

person Marcin Grzejszczak    schedule 16.01.2017
comment
Вы правы, я только что попробовал последнюю версию, и она работает. Я использовал версию 1.0.11.RELEASE. - person Hans; 16.01.2017

Если кто-то читает это, потому что он застрял в использовании старой версии Spring Sleuth, вы можете настроить планирование задач следующим образом. (Код должен находиться в классе @Configuration @EnableScheduling, который реализует SchedulingConfigurer). Это работает для меня до сих пор.

@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
    taskRegistrar.setTaskScheduler(taskScheduler());
}

// Declare this as a bean so that Spring shuts it down.
@Bean
public LazyTraceTaskScheduler taskScheduler() {
    ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
    // scheduledThreadCount is an auto-wired @Value for me, from application.properties.
    // You can just hard-code it.
    taskScheduler.setPoolSize(scheduledThreadCount);
    taskScheduler.setThreadNamePrefix("scheduled-");
    taskScheduler.setErrorHandler((throwable) -> 
        log.error("Uncaught error thrown by @Scheduled method", throwable));
    taskScheduler.shutdown();
    taskScheduler.initialize();
    return new LazyTraceTaskScheduler(beanFactory, taskScheduler);
}

private static class LazyTraceTaskScheduler implements TaskScheduler {

    private final BeanFactory beanFactory;
    private final ThreadPoolTaskScheduler delegate;
    private Tracer tracer;
    private TraceKeys traceKeys;
    private SpanNamer spanNamer;

    LazyTraceTaskScheduler(BeanFactory beanFactory, ThreadPoolTaskScheduler delegate) {
        this.beanFactory = beanFactory;
        this.delegate = delegate;
    }

    @Override
    public ScheduledFuture<?> schedule(Runnable task, Trigger trigger) {
        return delegate.schedule(newSpanContinuingTraceRunnable(task), trigger);
    }

    @Override
    public ScheduledFuture<?> schedule(Runnable task, Date startTime) {
        return delegate.schedule(newSpanContinuingTraceRunnable(task), startTime);
    }

    @Override
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period) {
        return delegate.scheduleAtFixedRate(newSpanContinuingTraceRunnable(task), startTime, period);
    }

    @Override
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long period) {
        return delegate.scheduleAtFixedRate(newSpanContinuingTraceRunnable(task), period);
    }

    @Override
    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Date startTime, long delay) {
        return delegate.scheduleWithFixedDelay(newSpanContinuingTraceRunnable(task), startTime, delay);
    }

    @Override
    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long delay) {
        return delegate.scheduleWithFixedDelay(newSpanContinuingTraceRunnable(task), delay);
    }

    public void shutdown() {
        delegate.shutdown();
    }

    private Runnable newSpanContinuingTraceRunnable(Runnable task) {
        if (isNull(tracer())) {
            // Due to some race conditions tracer, etc. might not be ready yet. See the code for LazyTraceExecutor.
            return task;
        }
        return new SpanContinuingTraceRunnable(tracer(), traceKeys(), spanNamer(), task);
    }

    private Tracer tracer() {
        if (isNull(tracer)) {
            try {
                tracer = beanFactory.getBean(Tracer.class);
            } catch (NoSuchBeanDefinitionException e) {
                return null;
            }
        }
        return tracer;
    }

    private TraceKeys traceKeys() {
        if (isNull(traceKeys)) {
            try {
                traceKeys = beanFactory.getBean(TraceKeys.class);
            } catch (NoSuchBeanDefinitionException e) {
                return new TraceKeys();
            }
        }
        return traceKeys;
    }

    private SpanNamer spanNamer() {
        if (isNull(spanNamer)) {
            try {
                spanNamer = beanFactory.getBean(SpanNamer.class);
            } catch (NoSuchBeanDefinitionException e) {
                return new DefaultSpanNamer();
            }
        }
        return spanNamer;
    }
}
person whistling_marmot    schedule 22.08.2018