> For the complete documentation index, see [llms.txt](https://wannaqueen.gitbook.io/spring5/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://wannaqueen.gitbook.io/spring5/spring-boot/undefined-1/34./34.2-amqp.md).

# 34.2 AMQP by sh

**AMQP (Advanced Message Queuing Protocol)는 메시지 중심 미들웨어를 위한 플랫폼 중립적인 유선 수준의 프로토콜입니다.** Spring AMQP 프로젝트는 핵심 Spring 개념을 AMQP 기반 메시징 솔루션 개발에 적용합니다. Spring Boot는 **`spring-boot-starter-amqp` "Starter"를 포함하여 RabbitMQ를 통해 AMQP를 사용하기위한 몇 가지 편의를 제공합니다.**&#x20;

{% hint style="info" %}
MQ?&#x20;

* 프로그래밍에서 MQ는 프로세스 또는 프로그램 인스턴스가 데이터를 서로 교환할 때 사용하는 방법을 의미한다.

AMQP&#x20;

* MQ를 오픈 소스에 기반한 표준 프로토콜 (이 프로토콜을 구현한 MQ 제품들 중 하나가 RabbitMQ)
  {% endhint %}

### 34.2.1 RabbitMQ 지원

[**RabbitMQ**](https://www.rabbitmq.com/)**는 AMQP 프로토콜을 기반으로하는 가볍고, 신뢰할 수 있고, 확장 가능하며, 이식 가능한 메시지 브로커입니다. Spring은 `RabbitMQ`를 사용하여 AMQP 프로토콜을 통해 통신합니다.**&#x20;

**RabbitMQ 구성은 `spring.rabbitmq.*`의 외부 구성 등록 정보에 의해 제어됩니다.** 예를 들어 다음 섹션을 `application.properties`에 선언 할 수 있습니다.&#x20;

```
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=secret
```

컨텍스트에 `ConnectionNameStrategy`bean이 있으면 자동으로 구성된 `ConnectionFactory`에 의해 작성된 연결의 이름을 지정하는 데 자동으로 사용됩니다. 지원되는 옵션에 대한 자세한 내용은 [`RabbitProperties`](https://github.com/spring-projects/spring-boot/tree/v2.1.5.RELEASE/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java)를 참조하십시오.

| ![\[Tip\]](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/images/tip.png)                                                           |
| --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 자세한 내용은 [Understanding AMQP, the protocol used by RabbitMQ](https://spring.io/blog/2010/06/14/understanding-amqp-the-protocol-used-by-rabbitmq/)를 참조하십시오. |

###

### 34.2.2 메시지 전송

**Spring의 `AmqpTemplate`과 `AmqpAdmin`은 자동으로 구성되므로 다음 예제와 같이 직접 bean에 autowire 할 수 있습니다.**&#x20;

```java
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

	private final AmqpAdmin amqpAdmin;
	private final AmqpTemplate amqpTemplate;

	@Autowired
	public MyBean(AmqpAdmin amqpAdmin, AmqpTemplate amqpTemplate) {
		this.amqpAdmin = amqpAdmin;
		this.amqpTemplate = amqpTemplate;
	}

	// ...

}
```

| ![\[Note\]](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/images/note.png)                                                                                                                                           |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`RabbitMessagingTemplate`](https://docs.spring.io/spring-amqp/docs/current/api/org/springframework/amqp/rabbit/core/RabbitMessagingTemplate.html)도 비슷한 방식으로 주입 할 수 있습니다. `MessageConverter`bean이 정의되면 자동으로 구성된 `AmqpTemplate`에 자동으로 연관됩니다. |

**필요한 경우 bean으로 정의 된 `org.springframework.amqp.core.Queue`는 자동으로 RabbitMQ 인스턴스의 해당 대기열을 선언하는 데 사용됩니다.**&#x20;

작업을 다시 시도하려면 `AmqpTemplate`에서 재시도를 활성화 할 수 있습니다 (예 : 브로커 연결이 끊어진 경우).

```
spring.rabbitmq.template.retry.enabled=true
spring.rabbitmq.template.retry.initial-interval=2s
```

재 시도는 기본적으로 비활성화되어 있습니다. `RabbitRetryTemplateCustomizer`Bean을 선언하여 `RetryTemplate`을 프로그래밍 방식으로 사용자 정의 할 수도 있습니다.&#x20;

### 34.2.3 메시지 수신&#x20;

**Rabbit 인프라 스트럭처가 존재하면 모든 Bean에 `@RabbitListener`가 어노테이션 처리되어 리스너 끝점을 만들 수 있습니다.** `RabbitListenerContainerFactory`가 정의되어 있지 않으면 기본 `SimpleRabbitListenerContainerFactory`가 자동으로 구성되며 `spring.rabbitmq.listener.type` 속성을 사용하여 직접 컨테이너로 전환 할 수 있습니다. `MessageConverter`또는 `MessageRecoverer`bean이 정의되면 자동으로 기본 팩토리와 연관됩니다.&#x20;

다음 샘플 컴포넌트는 `someQueue`큐에 리스너 엔드 포인트를 작성합니다.&#x20;

```java
@Component
public class MyBean {

	@RabbitListener(queues = "someQueue")
	public void processMessage(String content) {
		// ...
	}

}
```

| ![\[Tip\]](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/images/tip.png)                                                                     |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 자세한 내용은 [the Javadoc of `@EnableRabbit`](https://docs.spring.io/spring-amqp/docs/current/api/org/springframework/amqp/rabbit/annotation/EnableRabbit.html)을 참조하십시오. |

**더 많은 `RabbitListenerContainerFactory`인스턴스를 생성해야하거나 기본 설정을 덮어 쓰려면 SpringBoot가 `DirectRabbitListenerContainerFactoryConfigurer`와 `DirectRabbitListenerContainerFactoryConfigurer`를 제공합니다. 자동 구성에서 사용되는 팩토리와 동일한 설정으로 a`SimpleRabbitListenerContainerFactory`및 `DirectRabbitListenerContainerFactory`를 초기화하는 데 사용할 수 있습니다.**&#x20;

| ![\[Tip\]](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/images/tip.png) |
| ----------------------------------------------------------------------------------------------- |
| 선택한 컨테이너 유형은 중요하지 않습니다. 이 두 빈은 자동 구성에 의해 노출됩니다.                                                 |

예를 들어, 다음 구성 클래스는 특정 `MessageConverter`를 사용하는 다른 팩토리를 노출합니다.

```java
@Configuration
static class RabbitConfiguration {

	@Bean
	public SimpleRabbitListenerContainerFactory myFactory(
			SimpleRabbitListenerContainerFactoryConfigurer configurer) {
		SimpleRabbitListenerContainerFactory factory =
				new SimpleRabbitListenerContainerFactory();
		configurer.configure(factory, connectionFactory);
		factory.setMessageConverter(myMessageConverter());
		return factory;
	}

}
```

다음 예제처럼 **`@RabbitListener`-annotated 메서드에서 팩토리를 사용할 수 있습니다.**

```java
@Component
public class MyBean {

	@RabbitListener(queues = "someQueue", containerFactory="myFactory")
	public void processMessage(String content) {
		// ...
	}

}
```

**리스너가 예외를 throw하는 상황을 처리하도록 재 시도를 활성화 할 수 있습니다.**&#x20;

{% hint style="info" %}
메시지는 메시지를 받아간 worker가 정상적으로 작업을 끝마치면 RabbigMQ로 ack를 날리고, RabbitMQ는 메시지를 Queue에서 삭제하는 게 일반적인 동작!

예외가 발생하면 ack를 못받으니까 메시지를 삭제하지 못하고 계속 worker에게 전달되는 현상 발생.

**------> 이 때(worker가 정상적으로 작업을 끝마치지 못했을 경우), 정해진 횟수만큼 재시도 하도록 설정 변경 가능 (RetryTemplate 사용)**&#x20;
{% endhint %}

기본적으로 **`RejectAndDontRequeueRecoverer`가 사용되지만 사용자 자신의 `MessageRecoverer`를 정의 할 수 있습니다.** 재 시도가 고갈되면 브로커가 그렇게하도록 구성된 경우 메시지가 거부되고 데드 레터 교환으로 라우팅되거나 라우팅됩니다. 기본적으로 재시도 기능은 비활성화되어 있습니다. `RabbitRetryTemplateCustomizer`Bean을 선언하여 `RetryTemplate`을 프로그래밍 방식으로 사용자 정의 할 수도 있습니다.

{% hint style="info" %}
Recoverer : 익셉션 처리!
{% endhint %}

![](https://3140643518-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LWdhssr0w9IqAHmA-ke%2F-LhOaX3PklDZW0DEM-z5%2F-LhOcvSS0JQ348rf8xbJ%2Fimage.png?alt=media\&token=e204d8bc-9c13-48a2-b6e3-6da7e11e5eee)

{% hint style="info" %}
RejectAndDontRequeueRecoverer를 상속받는 Recoverer를 구현하면 caller에 익셉션을 전달할 때 Recoverer의 recover 메소드가 호출된다. 인자로 메시지와 예외를 받을 수 있기 때문에 예외 처리를 할 수 있으며 ReQueuing이 되지 않기 때문에 Queue에 메시지를 다시 쌓지 않는다.
{% endhint %}

| ![\[Important\]](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/images/important.png)                                                                                                                                                      | Important |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |
| 기본적으로 재시도가 사용되지 않고 리스너에서 예외가 발생하면 배달이 무기한 재 시도됩니다. 이 동작은 다음 두 가지 방법으로 수정할 수 있습니다. `defaultRequeueRejected` 속성을 `false`로 설정하여 재 배달을 재 시도하지 않거나 `AmqpRejectAndDontRequeueException`을 throw하여 메시지를 거부해야 함을 알립니다. 후자는 재시도가 사용 가능하고 최대 전달 시도 횟수에 도달 할 때 사용되는 메커니즘입니다. |           |
