Spring in Action Covers Spring 5-1--11 — страница 45 из 63

Чтобы получить удовольствие от Spring Integration, вы создадите поток интеграции, который записывает данные в файловую систему. Для начала вам нужно добавить Spring Integration в ваш проект. Для Maven необходимы следующие зависимости:

org.springframework.boot

spring-boot-starter-integration

org.springframework.integration

spring-integration-file

Первая зависимость - это стартер Spring Boot для Spring Integration. Эта зависимость важна для разработки потока Spring Integration, независимо от того, с чем он будет интегрироваться. Как и все starter зависимости Spring Boot, он доступен в виде флажка в форме Initializr.

Вторая зависимость - для файла Spring Integration endpoint модуля. Этот модуль является одним из более двух десятков endpoint модулей, используемых для интеграции с внешними системами. Мы поговорим подробнее о endpoint модулях в разделе 9.2.9. Но на данный момент известно, что endpoint модуль файлов предлагает возможность загружать файлы из файловой системы в поток интеграции и / или записывать данные из потока на файловую систему.

Затем необходимо создать способ для приложения, чтобы отправить данные в поток интеграции, так что он может быть записан в файл. Для этого вы создадите интерфейс шлюза, например, показанный ниже.

Листинг 9.1 Интерфейс шлюза сообщений для преобразования вызовов методов в сообщения

package sia5;

import org.springframework.integration.annotation.MessagingGateway;

import org.springframework.integration.file.FileHeaders;

import org.springframework.messaging.handler.annotation.Header;

@MessagingGateway(defaultRequestChannel="textInChannel") //Объявляет шлюз сообщений

public interface FileWriterGateway {

    void writeToFile(@Header(FileHeaders.FILENAME) String filename,String data); //Пишет в файл

}

Хотя это простой Java интерфейс, о FileWriterGateway можно многое сказать. Первое, что вы заметите, это то, что он аннотирован @MessagingGateway. Эта аннотация указывает Spring Integration на создание реализации этого интерфейса должно поисходить во время выполнения - подобно тому, как Spring Data автоматически генерирует реализации интерфейсов репозитория. Другие части кода будут использовать этот интерфейс, когда им нужно будет переписать файл.

Атрибут defaultRequestChannel @MessagingGateway указывает, что любые сообщения, полученные в результате вызова методов интерфейса, должны быть отправлены в данный канал сообщений. В этом случае вы заявляете, что любые сообщения, возникающие в результате вызова writeToFile(), должны отправляться на канал, имя которого textInChannel.

Что касается метода writeToFile(), он принимает имя файла в виде String и String, содержащий текст, который должен быть записан в файл. Что примечательно в сигнатуре этого метода, так это то, что параметр имени файла аннотирован @Header. В этом случае аннотация @Header указывает, что значение, переданное в filename, должно быть помещено в заголовок сообщения (указанный как FileHeaders.FILENAME, который разрешается в file_name), а не в полезную нагрузку сообщения. Значение параметра data, помещается в полезную нагрузку сообщения.

Теперь, когда у вас есть шлюз сообщений, вам нужно настроить интеграционный поток. Несмотря на то, что начальная зависимость Spring Integration, которую вы добавили в свою сборку, обеспечивает необходимую автоконфигурацию для Spring Integration, вы все равно должны написать дополнительные конфигурации, чтобы определить потоки, отвечающие потребностям приложения. Вот три варианта конфигурации для объявления потоков интеграции:

-XML конфигурация 

-Java конфигурация

- Java конфигурация с DSL

Мы рассмотрим все три из этих стилей конфигурации для Spring Integration, начиная с устаревшей конфигурации XML.

9.1.1 Определение потоков интеграции через XML

Хотя я избегал использования конфигурации XML в этой книге, Spring Integration имеет долгую историю интеграционных потоков, определенных в XML. Поэтому я считаю, что мне стоит показать хотя бы один пример потока интеграции, определенного через XML. В следующем списке показано, как настроить пример потока через XML.

Листинг 9.2 Определение потоков интеграции через XML

     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

     xmlns:int="http://www.springframework.org/schema/integration"

     xmlns:int-file="http://www.springframework.org/schema/integration/file"

     xsi:schemaLocation="http://www.springframework.org/schema/beans

     http://www.springframework.org/schema/beans/spring-beans.xsd

     http://www.springframework.org/schema/integration

     http://www.springframework.org/schema/integration/spring-integration.xsd

     http://www.springframework.org/schema/integration/file

     http://www.springframework.org/schema/integration/file/springintegration-file.xsd">

//Объявление textInChannel

     input-channel="textInChannel"

     output-channel="fileWriterChannel"

     expression="payload.toUpperCase()" /> // Преобразование текста

  //Объявление fileWriterChanne

      channel="fileWriterChannel"

      directory="/tmp/sia5/files"

      mode="APPEND"

      append-new-line="true" />  //Записывает текст в файл

Детализация XML в листинге 9.2:

Настаиваем канал с именем textInChannel. Это тот же канал что установлен для запроса FileWriterGateway. При вызове метода writeToFile() в FileWriterGateway, результирующее сообщение публикуется на этом канале.

Настроили преобразователь (transformer), который получает сообщения от textInChannel. Он использует выражение Spring Expression Language (SpEL) для вызова toUpperCase() в полезной нагрузке сообщения. Результат операции верхнего регистра затем публикуется в fileWriterChannel.

Настроили  канал с именем fileWriterChannel. Этот канал служит проводником, который соединяет transformer с адаптером исходящего канала.

Наконец, настроили адаптер исходящего канала, используя пространство имен int-file. Это пространство имен XML предоставляется модулем Spring Integration для записи файлов. Он настроен так что получает сообщения от fileWriterChannel и записывает полезные данные сообщения в файл, имя которого указано в заголовке file_name сообщения в каталоге, указанном в атрибуте каталога. Если файл уже существует, в него будут добавлены новые данные, а не перезаписан.

Этот поток показан на рис. 9.1 с использованием графических элементов, стилизованных под Enterprise Integration Patterns.

Шлюз записи файлов - Текст в канале - Uppercase transformer - Канал записи файлов - Адаптер исходящего канала файла

Рисунок 9.1 Поток интеграции записи файлов

Если вы хотите использовать конфигурацию XML в приложении Spring Boot, вам необходимо импортировать XML как ресурс в приложение Spring. Самый простой способ сделать это - использовать аннотацию Spring @ImportResource в одном из классов конфигурации вашего приложения:

@Configuration 

@ImportResource("classpath:/filewriter-config.xml") 

public class FileWriterIntegrationConfig { ... }

Хотя конфигурация на основе XML хорошо послужила Spring Integration, большинство разработчиков опасаются использовать XML. (И, как я уже сказал, я избегаю конфигурации через XML в этой книге.) Давайте отложим эти угловые скобки и обратим наше внимание на стиль конфигурации через Java в Spring Integration.

9.1.2 Настройка потоков интеграции через Java

Большинство современных приложений Spring отказались от конфигурации XML в пользу конфигурации Java. Фактически в приложениях Spring Boot конфигурация Java является естественным стилем, дополняющим автоконфигурацию. Поэтому, если вы добавляете поток интеграции в приложение Spring Boot, имеет смысл определить поток посредством Java.

В качестве примера того, как написать поток интеграции используя Java конфигурацию, взгляните на следующий листинг. Это показывает тот же процесс интеграции записи файлов, что и раньше, но на этот раз он написан на Java.

package sia5;

import java.io.File; import org.springframework.context.annotation.Bean; 

import org.springframework.context.annotation.Configuration;

import org.springframework.integration.annotation.ServiceActivator; 

import org.springframework.integration.annotation.Transformer; 

import org.springframework.integration.file.FileWritingMessageHandler; 

import org.springframework.integration.file.support.FileExistsMode;

 import org.springframework.integration.transformer.GenericTransformer; 

@Configuration 

public class FileWriterIntegrationConfig {

    @Bean

    @Transformer(inputChannel="textInChannel", //Объявляем transformer

                outputChannel="fileWriterChannel")

    public GenericTransformer upperCaseTransformer() {

        return text -> text.toUpperCase();

    }

    @Bean

    @ServiceActivator(inputChannel="fileWriterChannel")

    public FileWritingMessageHandler fileWriter() { //Объявляем запись в файл

        FileWritingMessageHandler handler =

                    new FileWritingMessageHandler(new File("/tmp/sia5/files"));

        handler.setExpectReply(false);

        handler.setFileExistsMode(FileExistsMode.APPEND);

        handler.setAppendNewLine(true);

        return handler;

    }