手順など
pom.xml
コメントアウトの箇所は後述。
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.0.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>13</maven.compiler.source> <maven.compiler.target>13</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> <!-- <dependency> --> <!-- <groupId>org.springframework.boot</groupId> --> <!-- <artifactId>spring-boot-starter-json</artifactId> --> <!-- </dependency> --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
application.properties
src/main/resources/application.properties
にrabbitmqへの接続設定を記述する。
spring.rabbitmq.host=localhost spring.rabbitmq.port=5672 spring.rabbitmq.username=xxxx spring.rabbitmq.password=xxxx
送受信するPOJO
適当なクラスを作る。特に深い意味は無いけどlombokは使っていないので、コンストラクタ・getter/setterは省略。
import java.io.Serializable; import java.util.List; public class Parent implements Serializable { private static final long serialVersionUID = 1L; String id; List<Child> childs; //コンストラクタ・getter/setterは省略 }
import java.io.Serializable; public class Child implements Serializable { private static final long serialVersionUID = 1L; String id; //コンストラクタ・getter/setterは省略 }
send/receive
以下がエントリポイント。また、起動するとCommandLineRunner
で送信を行いrecievedMessage
で受信を待ち受ける。以下のクラスを実行すると送受信が行われる。
コメントアウト箇所については後述。
import java.util.List; import org.springframework.amqp.core.AmqpTemplate; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; @SpringBootApplication public class App implements CommandLineRunner { public static void main(String[] args) { new SpringApplicationBuilder(App.class).web(WebApplicationType.NONE).run(args); } @Autowired AmqpTemplate amqpTemplate; @Override public void run(String... args) throws Exception { var message = new Parent("id12345", List.of(new Child("1"), new Child("2"), new Child("3"))); amqpTemplate.convertAndSend("test-exchange", "", message); } // @Bean // public MessageConverter jsonMessageConverter(){ // return new Jackson2JsonMessageConverter(); // } @RabbitListener(queues="test-queue") public void recievedMessage(Parent company) { System.out.println("company.id = " + company.id); company.childs.forEach(c -> System.out.println("child.id = " + c.id)); } }
管理画面でメッセージを確認
RabbitMQの管理画面から見ると、以下のようにメッセージはバイナリで人間の眼では読めない形式になっている。
JSONで送受信
次に、送受信するPOJOをJSON形式に変更する。変更するには、上述のソースでコメントアウトの箇所を外す。
pom.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-json</artifactId> </dependency>
App.java
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; import org.springframework.amqp.support.converter.MessageConverter; @Bean public MessageConverter jsonMessageConverter(){ return new Jackson2JsonMessageConverter(); }
上記変更を加えた後、実行してRabbitMQの管理画面から見ると、以下のようにメッセージがJSON形式になるのが確認できる。
はまった点
Caused by: java.lang.ClassNotFoundException: com.fasterxml.jackson.databind.ObjectMapper
JSONで送受信する場合、pom.xmlにspring-boot-starter-json
の依存性を追加しないと、以下のような実行時エラーが発生する。
Caused by: java.lang.ClassNotFoundException: com.fasterxml.jackson.databind.ObjectMapper at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:602) ~[na:na] at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178) ~[na:na]
SimpleMessageConverter only supports String, byte[] and Serializable payloads
バイナリ形式で送受信する場合、POJOにSerializable
をimplementsする必要がある。JSONの場合はSerializable
は要らない。
Caused by: java.lang.IllegalArgumentException: SimpleMessageConverter only supports String, byte[] and Serializable payloads, received: kagami.amqp.Parent at org.springframework.amqp.support.converter.SimpleMessageConverter.createMessage(SimpleMessageConverter.java:161) ~[spring-amqp-2.2.0.RELEASE.jar:2.2.0.RELEASE]
No serializer found for class kagami.amqp.Parent and no properties discovered to create BeanSerializer
POJOにgetter/setterが無い、あるいは、publicプロパティが無い場合に以下のような実行時エラーが発生する。
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class kagami.amqp.Parent and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) ~[jackson-databind-2.10.0.jar:2.10.0] at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1191) ~[jackson-databind-2.10.0.jar:2.10.0]