spring-cloud / spring-cloud-stream-samples

Samples for Spring Cloud Stream
Apache License 2.0
959 stars 677 forks source link

Inability to infuse #167

Closed ChenZheOnePiece closed 4 years ago

ChenZheOnePiece commented 4 years ago

I copy the following

    @Autowired
    @Qualifier("oddEvenSupplier-out-0")
    MessageChannel outputDestination;

but i can't Autowired this is my code


@SpringBootApplication
@RestController
public class StreamfunctionApplication {
    private static Logger logger = LoggerFactory.getLogger(StreamfunctionApplication.class);
    public static void main(String[] args) {
        SpringApplication.run(StreamfunctionApplication.class, args);
    }

    @Autowired
    @Qualifier("receive-in-0")
    private MessageChannel input;

    @Autowired
    @Qualifier("transform-out-0")
    private MessageChannel output;

    @RequestMapping(value = "/test")
    public void test(@RequestBody String msg) {
        input.send(new GenericMessage<>(msg));
    }
    @Bean
    public Function<String, String> transform() {
        return payload -> payload.toUpperCase();
    }

    //Following source is used as a test producer.
    static class TestSource {

        private AtomicBoolean semaphore = new AtomicBoolean(true);

        @Bean
        public Supplier<String> sendTestData() {
            return () -> this.semaphore.getAndSet(!this.semaphore.get()) ? "foo" : "bar";

        }
    }

    //Following sink is used as a test consumer.
    static class TestSink {

        @Bean
        public Consumer<String> receive() {
            return payload -> logger.info("Data received: " + payload);
        }
    }
}
spring:
  cloud:
    stream:
      function:
        definition: transform;sendTestData;receive
      bindings:
        transform-out-0:
          destination: xformed
        receive-in-0:
          destination: xformed
        transform-in-0:
          destination: testtock
        sendTestData-out-0:
          destination: testtock
artembilan commented 4 years ago

Those MessageChannel injections must be marked with the @Lazy:

 * <p>In addition to its role for component initialization, this annotation may also be placed
 * on injection points marked with {@link org.springframework.beans.factory.annotation.Autowired}
 * or {@link javax.inject.Inject}: In that context, it leads to the creation of a
 * lazy-resolution proxy for all affected dependencies, as an alternative to using
 * {@link org.springframework.beans.factory.ObjectFactory} or {@link javax.inject.Provider}.

It turns out that you have an injection in the same class where you provide beans for them, but since it is not direct bean creation, but rather late binding, those channels are not available as beans in early autowiring phase. So, postponing an interaction with field to the later action is the way to go for your sample.

ChenZheOnePiece commented 4 years ago

Thank you very much. You solved my problem .It makes me very happy. I hope you are in good health i don't kown why Under spring-cloud-stream-samples , testing-demo why at the class can not use LAZY . I Think in the class add some Tips is better. This will save other people's time

@SpringBootTest(
        webEnvironment = SpringBootTest.WebEnvironment.NONE,
        properties = "spring.cloud.stream.poller.fixed-delay=1")
@ImportAutoConfiguration(exclude = {
        KafkaAutoConfiguration.class,
        KafkaMetricsAutoConfiguration.class,
        DataSourceAutoConfiguration.class,
        TransactionAutoConfiguration.class,
        DataSourceTransactionManagerAutoConfiguration.class })
@DirtiesContext
class OddEvenSourceTests {

    @Autowired
    @Qualifier("oddEvenSupplier-out-0")
    MessageChannel outputDestination;

    @Autowired
    MessageCollector collector;

    @Test
    void testMessages() {
        BlockingQueue<Message<?>> messages = this.collector.forChannel(this.outputDestination);

        assertThat(messages, receivesPayloadThat(is("odd")));
        assertThat(messages, receivesPayloadThat(is("even")));
        assertThat(messages, receivesPayloadThat(is("odd")));
        assertThat(messages, receivesPayloadThat(is("even")));
    }

}
artembilan commented 4 years ago

It works in tests because the test configuration is populated in the end, when the application context is ready already. Therefore all the beans are available for autowiring.

ChenZheOnePiece commented 4 years ago

thanks