Статьи

Spring Integration — Сессия 2 — Больше Hello Worlds

Это продолжение весенней сессии интеграции 1

Первая сессия была простым приложением Hello World, использующим Spring Integration. Я хочу пойти немного дальше, рассмотрев еще несколько сценариев вокруг этого.

Итак, первое изменение в приложении Hello World — добавить компонент Gateway. Чтобы быстро вернуться к предыдущей тестовой программе:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package org.bk.si.helloworld.hw1;
 
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.message.GenericMessage;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("helloworld.xml")
public class HelloWorldTest {
  
 @Autowired
 @Qualifier("messageChannel")
 MessageChannel messageChannel;
 
 @Test
 public void testHelloWorld() {
  Message<String> helloWorld = new GenericMessage<String>("Hello World");
  messageChannel.send(helloWorld);
 }
}

В выделенных выше строках тест зависит от конкретного компонента Spring Integration — канала сообщений, а в тесте создается явное сообщение интеграции Spring и отправляется в канал сообщений. Слишком тесная связь с Spring Integration, которая здесь является системой обмена сообщениями.

Компонент Gateway обеспечивает фасад для системы обмена сообщениями, защищая пользовательское приложение (в данном случае модульное тестирование) от деталей системы обмена сообщениями — канала обмена сообщениями, Message и явной отправки сообщения.

Сначала приведем пример того, как будет выглядеть тест с компонентом Gateway:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
package org.bk.si.helloworld.hw2;
 
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 
 
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("helloworld.xml")
public class HelloWorldTest {
 
 @Autowired Greeter greeter;
 
 @Test
 public void testHelloWorld(){
   this.greeter.sendGreeting("Hello World");
 }
}

Приведенный выше интерфейс Greeter является компонентом Gateway. Теперь, когда этот компонент был представлен, в этом тесте нет зависимости от Spring Integration — в коде вообще не упоминается Message, Message Channel.

Компонент Gateway также является очень простым Java-интерфейсом, определенным следующим образом:

1
2
3
4
5
package org.bk.si.helloworld.hw2;
 
public interface Greeter {
 public void sendGreeting(String message);
}

Итак, теперь вопрос в том, кто позаботится о создании сообщений и отправке сообщений в канал сообщений — это через конфигурацию Spring Integration:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
 
 
 <int:channel id="messagesChannel"></int:channel>
  
 <int:gateway service-interface="org.bk.si.helloworld.hw2.Greeter" default-request-channel="messagesChannel"></int:gateway>
  
 <int-stream:stdout-channel-adapter channel="messagesChannel" append-newline="true"/>
  
 
</beans>

Выделенная строка выше создает компонент Gateway из интерфейса Greeter, в фоновом режиме создается прокси-сервер, который обрабатывает все, что было сделано ранее — создание сообщений и отправка сообщений в канал сообщений.

Теперь добавим немного большей сложности к примеру Hello World:

Рассмотрим следующий тест:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package org.bk.si.helloworld.hw3;
 
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 
 
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("helloworld.xml")
public class HelloWorldTest {
 
 @Autowired Greeter greeter;
 
 @Test
 public void testHelloWorld(){
  System.out.println("Started..");
  long start = System.nanoTime();
  for (int i=0;i<10;i++){
   this.greeter.sendMessage(String.format("Hello World %d",i));
  }
  System.out.println("Completed..");
  System.out.println(String.format("Took %f ms", (System.nanoTime()-start)/10e6));
 }
}

Это то же самое, что и предыдущий модульный тест, за исключением того, что в этом случае сообщение «Hello World» отправляется 10 раз. Поддерживающий конфигурационный файл Spring Integration:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
 
 
 <int:publish-subscribe-channel id="messagesChannel"/>
 <int:gateway service-interface="org.bk.si.helloworld.hw3.Greeter" default-request-channel="messagesChannel"></int:gateway>
  
  
 <int-stream:stderr-channel-adapter channel="messagesChannel" append-newline="true"/>
 <int-stream:stdout-channel-adapter channel="messagesChannel" append-newline="true"/>
  
</beans>

Если я сейчас запущу этот тест, результат будет таким:

Красные линии печатаются в syserr, а черные печатаются в sysout.

Итак, вопрос в том, почему некоторые из них собираются на sysout, а некоторые — на syserr, а почему нет — на оба?

Ответ из-за типа канала — «messagesChannel» выше является «Прямым каналом» в терминологии Spring Integration и имеет семантику «точка-точка». Семантика точка-точка в основном означает, что когда сообщение поступает в канал обмена сообщениями, только 1 получатель получает сообщение — так что в этом случае либо стандартный выходной адаптер, либо стандартный адаптер ошибки заканчивает тем, что печатает сообщение, поступающее в Канал сообщений.

Таким образом, для печати на обоих адаптерах необходимо просто изменить семантику канала — вместо канала «точка-точка» сделать его каналом публикации-подписки, который является каналом, передающим сообщение нескольким получателям. Изменение очень просто с помощью Spring Integration:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
file:/C:/learn/scratch/target/test-classes/org/bk/htmlencode/content.txt
<?xml version="1.0" encoding="UTF-8"?>
 
 
 <int:publish-subscribe-channel id="messagesChannel"/>
 <int:gateway service-interface="org.bk.si.helloworld.hw3.Greeter" default-request-channel="messagesChannel"></int:gateway>
  
  
 <int-stream:stderr-channel-adapter channel="messagesChannel" append-newline="true"/>
 <int-stream:stdout-channel-adapter channel="messagesChannel" append-newline="true"/>
  
</beans>

Теперь выводом будут сообщения, которые печатаются в ОБА sysout и syserr

Таким образом, на этом заканчивается введение в компонент шлюза, прямой канал и канал публикации подписки.

Ссылка: Spring Integration — Сессия 2 — Больше Hello Worlds от нашего партнера JCG Биджу Кунджуммен в блоге all and sundry.