Wednesday, 25 December 2019

This week 2/2019 - Spring Integration


This is my first meet with Spring Integration. I started with version 4.3 so I will not mention of older version which I don't know.
For whom who don't know what is it Spring Integration. In a nutshell, this is a framework to create flows between betweens input adapters and endpoints.

In a short story I describe what I'd like to reach.

I've got some configuration in XML version which is included in to class version of configuration. I have as well test context (class version) which override some beens - adapters from/to external world). I'd like to translate this XML to have:
  • consistent configuration in production and test code,
  • to be able override production configuration of some adapters (ex. file adapters)
  • to use inline transformations (not included in example).
Below I added a sample of configuration for class version and commented out a equivalent XML code.



  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
@Configuration
//@ImportResource("/spring-int.xml")
@EnableIntegration
public class IntConfig {


//    <int:channel id="inChannel"/>

//    <int:transformer input-channel="inChannel"
//                     output-channel="srcEmailChannel"
//                     ref="inTransformer"/>
//    <bean id="inTransformer" class="PublisherTransformer"/>
//

    @Bean
    @Transformer(inputChannel = "inChannel", outputChannel = "srcEmailChannel")
    PublisherTransformer inTransformer() {
        return new PublisherTransformer();
    }

//    <int:channel id="srcEmailChannel">
//        <int:interceptors>
//            <int:wire-tap channel="backup"></int:wire-tap>
//        </int:interceptors>
//    </int:channel>


    @Bean
    public MessageChannel backup() {
        return new DirectChannel();
    }

    @Bean
    public MessageChannel srcEmailChannel() {
        final DirectChannel directChannel = new DirectChannel();
        directChannel.addInterceptor(new WireTap(backup()));
        return directChannel;
    }


//    <int:router input-channel="backup" expression="headers.country">
//        <int:mapping value="PL" channel="plChannel"/>
//        <int:mapping value="EN" channel="enChannel"/>
//    </int:router>

    @Bean
    @Router(inputChannel = "backup")
    public AbstractMessageRouter backupRouter() {
        HeaderValueRouter router = new HeaderValueRouter("country");
        router.setChannelMapping("PL", "plChannel");
        router.setChannelMapping("EN", "enChannel");
        return router;
    }


//    <int:channel id="plChannel"/>
//    <int-file:outbound-channel-adapter id="plChannelOutFile"
//                                       directory="/tmp/plChannel/"
//                                       channel="plChannel"
//                                       mode="APPEND"
//                                       charset="UTF-8"/>

    @Bean
    @ServiceActivator(inputChannel = "plChannel")
    MessageHandler plChannelOutFile() {
        final FileWritingMessageHandler fileWritingMessageHandler = 
                new FileWritingMessageHandler(new File("/tmp/plChannel/"));
        fileWritingMessageHandler.setCharset(UTF_8);
        fileWritingMessageHandler.setFileExistsMode(APPEND);
        fileWritingMessageHandler.setExpectReply(false);
        return fileWritingMessageHandler;
    }

//    <int:channel id="enChannel"/>
//    <int-file:outbound-channel-adapter  id="enChannelOutFile"
//                                        directory="/tmp/enChannel/"
//                                        channel="enChannel"
//                                        mode="APPEND"
//                                        filename-generator="fileGenerator"
//                                        charset="UTF-8"/>
//    <bean id="fileGenerator" class="FileNameGen"/>

    @Bean
    @ServiceActivator(inputChannel = "enChannel")
    MessageHandler enChannelOutFile() {
        final FileWritingMessageHandler fileWritingMessageHandler = 
                new FileWritingMessageHandler(new File("/tmp/enChannel/"));
        fileWritingMessageHandler.setCharset(UTF_8);
        fileWritingMessageHandler.setFileExistsMode(APPEND);
        fileWritingMessageHandler.setExpectReply(false); // I don't need return
        fileWritingMessageHandler.setFileNameGenerator(new FileNameGen());
        return fileWritingMessageHandler;
    }


//    <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl"/>
      // this not complete mail server configutation
      @Bean
      MailSender mailSender() {       
          return new JavaMailSenderImpl();
      }
//
//
//    <int-mail:outbound-channel-adapter channel="srcEmailChannel" mail-sender="mailSender"/>
    @Bean
    @ServiceActivator(inputChannel = "srcEmailChannel")
    MessageHandler messageHandler(MailSender mailSender) {
       return new MailSendingMessageHandler(mailSender);
    }
    @Bean
    PublisherService publisherService() {
        return new PublisherService();
    }
}

As you can see all of used channels must be defined manualy in XML version. In class version I defined only those which I'd like add some additional behaviour.

Is it true that in Java we can't change Spring Integration configuration with simple editor an restart applicaton - we need compile this configuration but we have plenty of possibilities to do.

Starting from version 5.0 there is additional implementation supporting mixed configuration in test, ex.
  • @SpringIntegrationTest
  • MockIntegrationContext
However this works in other way than overrding bean definition as I did it. This stops current MessageHandler lifecycle and replace condext with mocked bean.

In version 5 it was added as well DSL to make configuration more readable. More information in [1]


No comments:

Post a Comment