Adding Spring-Integration to a Boot application

This weeks post has some anecdotally value for me. 9 years ago I wrote a horrible tutorial about threads, which I really liked back then. In the meantime I often thought I should delete the post and only kept it around to prove some improvements on my side 😉

Anyway, the code in that tutorial has been the foundation for a module that is running for near as long as the blog post is old. My company uses it on several occasions for data transfer of all kind, being it files, checking emails or ftp servers and it works pretty well. The downside: It’s pretty much not maintainable, the code is bad and half the stuff or more I wrote can be replaced with messaging or a real service bus.

In the first iteration of rewrite I did exactly that: I used a Java Messaging Service implementation for moving stuff around and did the rest myself. Luckily this time I noticed…

Entering Spring Integration:

Extends the Spring programming model to support the well-known Enterprise Integration Patterns. Spring Integration enables lightweight messaging within Spring-based applications and supports integration with external systems via declarative adapters. Those adapters provide a higher-level of abstraction over Spring’s support for remoting, messaging, and scheduling. Spring Integration’s primary goal is to provide a simple model for building enterprise integration solutions while maintaining the separation of concerns that is essential for producing maintainable, testable code.

I really don’t care at the moment which backend or transport I use… As long as I know it’s swappable, I’m fine.

Getting up and running in a Spring Boot application is as easy as adding the dependencies

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-integration</artifactId>	    	
</dependency>
<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-file</artifactId>	  	
</dependency>
<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-java-dsl</artifactId>
    <version>1.1.2.RELEASE</version>
</dependency>
@SpringBootApplication
@EnableIntegration
public class Application {
}

Nothing fancy here.

You can either create your flows throw XML Definitions which has the benefit of being supported by Spring Tool Suite™ or as @Beans. For the later, you’ll find a nice sample here.

I opted for the bean version, mainly for one reason: I have to support multiple, differently configured instances of one or more flows.

I have a list of workflow builders (custom interface) in an @Configuration class that gets auto populated through @EnableConfigurationProperties and in a loop i use the method described in this GitHub issue:

@PostConstruct
void initializeWorkflows() {	
    this.workflowBuilders.stream().flatMap(workflowBuilder -> workflowBuilder.build().entrySet().stream()).forEach(workflow -> {
        beanFactory.registerSingleton(workflow.getKey(), workflow.getValue());
        beanFactory.initializeBean(workflow.getValue(), workflow.getKey());
    });	
}

The “Cafe Demo” helped a lot to get started with the Java DSL, especially the lambda version.

To demonstrate what is possible, I can show you my current task, which can be roughly explained as follow “Watch one ore more directories for a given tenant, detect CSV and excel files, split the sheets of excel sheets into separate content and load all contents into a database and call a stored procedure afterwards”.

The first part is really simple:

// 1
final FileListFilter<File> fileListFilter = new CompositeFileListFilter<>(Arrays.asList(
    new FileSystemPersistentAcceptOnceFileListFilter(this.metadataStore, "exceldatenaustausch:"),
    new FilesOnlyFileListFilter()		    
));
final FileReadingMessageSource reader = new FileReadingMessageSource();
reader.setDirectory(new File(s.directory));
reader.setFilter(fileListFilter);
 
// 2	            
IntegrationFlows
    .from(reader, endpoint -> endpoint.poller(Pollers.fixedRate(s.intervall, TimeUnit.SECONDS)))
    .enrich(enricher -> enricher
    	.header("tenant", s.tenant)
    	.<File>headerFunction("contentType", message -> contentTypeMap.getOrDefault(tika.detect(message.getPayload()), "unknown"))
    )
    .route(payload -> "exceldatenaustausch-incoming-channel")
    .get();
  1. Setup a file reading message source, that watches a directory, accepts only files and those only once
  2. Poll that reader every n seconds, add a tenant number and the content type to each file message and route them to a specific channel

And all the rest is easy as well:

IntegrationFlows
    .from("exceldatenaustausch-incoming-channel")
    // 1
    .filter("!headers.contentType.equals('unknown')")
    // 2
    .route("headers.contentType", mapping -> mapping
        .channelMapping("csv",   "read-csv-channel")
        .channelMapping("excel", "split-excel-channel")
    )
    .channel("read-csv-channel")
        // 3
        .transform(File.class, Strings::fromFile)
        .route(payload -> "store-content-channel")
    .channel("split-excel-channel")
        // 4
        .split(new ExcelSplitter(locale, linebreak, separator, dateFormat), "extractSheets")
        .enrich(enricher -> enricher
        	.<ExcelSheet>headerFunction("sheetName", message -> message.getPayload().getSheetName())
        	.<ExcelSheet>headerFunction("sheetNumber", message -> message.getPayload().getSheetNumber())
        )
        // 3
        .transform(ExcelSheet.class, ExcelSheet::getContent)
        .route(payload -> "store-content-channel")
    .channel("store-content-channel")
    // 5
    .<String>handle((content, headers) -> {
        return excelDatenaustauschRepository.add((Integer)headers.get("madantennr"), (String) headers.get("fileName") content);			
    })
    // 6
    .handle(this.excelDatenaustauschService, "callfExcelDatenaustausch")
    .<Long>handle((status, headers) -> {
        LOGGER.info("Stored {} and called F_EXCEL_DATENAUSTAUSCH with result {}.", headers.get("fileName"), status);
        return null;
    })
    .get();

We see here:

  1. Filtering based on SpEL expressions
  2. Routing based on SpEL expressions and following channel mappings
  3. Transformation of messages from files to strings
  4. Splitting of messages from one file into a list of other stuff
  5. Handling of messages with an explicit handler
  6. Handling of messages by an implicit bean method

I like the result of one week work very much: The stuff is actually readable. Even if I don’t have a nice visualization from an XML based configuration, one can understand the flow just from the code and that’s much more than I had with the nearly 10 year old homegrown solution. I also have the infrastructure in place, to distribute that flow (and others) along several services and switch transports if necessary without the need for any boilerplate code.

| Comments (0) »

29-Jun-16


IMPROVE

In der vergangenen Woche war ich in der glücklichen Situation, einen weiteren Kurs mit Gernot Starke, Peter Hruschka und Carola Lilienthal zu besuchen.

Der IMPROVE Kurs war nicht nur ein hervorragender Baustein im iSAQB CPSA Advanced Level, sondern ein hervorragender Austausch zwischen Entwicklern und engagierten Trainern.

Natürlich fand’ ich auch die konkreten Themen zum Refactoring auch spannend, aber nicht so sehr wie den Schwerpunkt auf Analyse (und auch wenn es schwer fällt, auf Evaluate).

Bzgl. Refactoring und dem Plädoyer von Carola, Architekturen bzw. Konzepte und Muster nicht nur “auf dem Papier” zu haben, sondern auch zu leben, reicht eigentlich schon diese Einschätzung alltäglicher Aufgaben:


aufgabenteilung

Die (bekannten?) Top 5 Gründe für Probleme / Issues in Softwaresystem und Software:

  1. Unrealistische Zeitpläne
  2. Feature Creep
  3. Mitarbeiterfluktuation
  4. Interessenskonflikte von Stakeholder
  5. Produktivitätsunterschiede (“10x Programmer”)

Eigentlich war ich ganz froh, dass die Unterlagen (unverschuldet) nicht pünktlich da waren, denn ich habe mir endlich noch mal was mitgeschrieben. Da ich leider nicht so toll zeichnen kann wie einige, habe ich die mir wichtigen Impulse mal in eine unsortierte Mindmap gebracht (das Bild ist mit einer PDF Datei verlinkt):

Was mir – wie auch im Foundation Kurs mit Peter und Gernot – gefallen und Spaß gemacht hat, waren die praktischen Übungen. Übungen, die einen aus der Komfortzone bringen und insbesondere von Peter mit gefühlt großen Vergnügen forciert werden.

Für mich nehme ich – bei allem Spaß am Programmieren und refactoren – mit, dass meine weiteren Schwerpunkte ganz bewusst auf Softskills liegen werden. Schon alleine in den Übungen merkte ich wieder, wie wichtig es ist, sich auf andere Menschen einzulassen. Jede Architektur ist in meinen Augen auch immer ein Abbild des oder der Menschen dahinter und insbesondere ihrer Art, miteinander zu kommunizieren.

Und im übrigen, der beste Spruch bzgl. misslungener Kommunikation hinsichtlich Projektstatus, den ich aufgeschnappt habe:

| Comments (0) »

23-Jun-16


NetBeans IDE plugin supporting programming with Spring Boot

There are several plugins out there for supporting Spring development in NetBeans, but the

NB-SpringBoot

by Alessandro Falappa seems to be the most feature complete. At the moment installation must be done via manual download from here but that should be fixed soon.

You’ll get a really nice Spring property support:


propertysupport

Great integration with start.spring.io:


startspringio.png

And also some useful templates for different Spring artifacts (just one hint, Alex, make the suggested name uppercase):


templates.png

I’m gonna pass this on to my colleagues and friends, I think it’s a very great addition to NetBeans.

| Comments (1) »

19-Jun-16


On dependency injection

Today is one of those days where I either react to short tempered or don’t get my point across:

This is what I’m experiencing those days, with some projects at work and also with Daily Fratze those days.

In younger (more current) projects I took really great care to avoid setter or attribute based dependency injection. You can do completely without – at least in a Spring based environment, where you can use an injectable entity manager as well.

There are enough blog posts out there that emphasize the advantages for testing, having only “complete” and ready to use instances in you hands and so on, but the above point is one of my personal main advantages.

When I first came across a real dependency injection framework nearly a decade ago I was like “wow, this is awesome!” and had suddenly @Autowired (or @Inject) at nearly every attribute and managed to create “god classes” in no time. At the beginning I still generated getters and setters as well… Not being aware, that the fields would be set via reflection anyway (removing them showed one flaw: How to test stuff without firing up the whole thing?).

Anyway, the “god classes”: Big piles of mud having a dozen collaborators or more and doing “everything”.

I’m not sure how that looks today with junior developers… Do they learn that stuff in university? Or is this temptation still real?



If you use constructor based injection you immediately get two advantages:

  • The pain of having a constructor with a dozen parameters, knowing that your thing *will* have too much responsibility.
  • A slap by your DI framework if you have circular dependencies.

Why use yet another tool in your build process to point out your obvious code smells when start up fails? If you really have to have that circle, there are ways (for example having a setter for that one dependency but than the “problem” is obvious and at last or framework dependent solutions).

Last but not least: You get dependency injection done right in my eyes, which is: no obvious need for a DI framework. You can construct and use your objects “by hand”, if you want to. That is especially true for the latest Spring Framework release 4.3, you can even omit the @Autowired on a unique, non default constructor.

The current problem I fixed today was like this: I have to create to entities that might depend on each other. For both creations I used a separate service and both services where directly accessing an entity manager and both where depending on each other (the one using the other for creating an instance, the other using the first for accessing stuff from the other entity). By introducing a data access layer in form of a Spring Data repository both could easily be decoupled. By further taking care that if a relationship between the two instances of the entities exist, the entities can only be instantiated completely (that is, fully populated, valid and ready to be persisted), I solved the circular dependency, got rid of an unnecessary BeanValidator in a service (I had to use a command object to call the other one) and remove somewhat along 40 lines of code.

| Comments (0) »

13-Jun-16


Talking about custom Spring Boot Starter at Spring I/O

2 weeks ago, i flew over to beautiful Barcelona, visiting Spring I/O, one of the (if not the) largest Spring and Groovy related conferences in Europe, primary organized by Sergi Almar.

I’m now running a user group for a year now which is mostly fun but takes some time if you want to do it right. I don’t want to imagine the work that Sergi pour into a full 2 day conference. Thanks a lot for it, it was well prepared and executed, from the speaker event, the event itself and the after show. Thanks a lot.

It was nice that my talked was scheduled right after the keynote, little time to build tension for me. The keynote by Stéphane Nicoll and Phillip Webb was really great and entertaining, though they said a lot about Boot that I wanted to mention 😉 Also Jürgen Höller was there and talked about present and future Spring and set the topic for larger parts of the conference: Reactive programming with Spring.

I was more than glad seeing Phillip and Stéphane at my talk and having their feedback. Thanks again. My talk was basically around about wether it’s “magic” or just really good design for extending Spring Boot and you’ll find it at my Github repository here: It’s a kind of magic? – Custom Spring Boot Starter:



Here’s a screenshot of the last step of the demo, in case you’ve missed it:



My conclusion: I’m very glad that I took the step “outside” my blog and I’ll happily do it again. In case you want me to speak at your JUG or similar event, just drop me a line.

The “rest” of the conference was really enjoyable. I learnt a lot about what “Reactive” actually is, what the current state of Spring Framework is and how the framework is evolved yet another time to work “as used to” and at the same time will be innovative. Listening to the people from the Spring core team was great and it was actually as kind as described here.

Daniel Fernández from the Thymeleaf project was there as well and spoke about the new features in Thymeleaf 3.0. I really like Thymeleaf (although I don’t think that JSPs have been bad, actually), but I wonder if it’s a good idea to extend Thymeleaf into doing JavaScript generation. We’ll see.

Here are some more posts I found about the conference:

Now I’m eagerly looking forward for the videos of the talks and pictures being uploaded somewhere… I’m really excited if I can stand to watch myself 🙂

| Comments (3) »

01-Jun-16