Spring 통합 및 Google Cloud Pub/Sub를 통한 메시징

1. 개요

Spring Integration은 MessageChannels를 통해 Messages를 교환하는 메시지 메커니즘을 제공합니다. 채널 어댑터를 사용하여 외부 시스템과 통신합니다.

이 연습에서는 Spring Cloud GCP에서 제공하는 Spring Integration 채널 어댑터를 사용하여 통신하는 두 개의 앱을 만들어 보겠습니다. 이러한 어댑터를 사용하면 Spring Integration에서 Google Cloud Pub/Sub를 메시지 교환 백엔드로 사용하게 됩니다.

Cloud Shell 및 Cloud SDK gcloud 명령어를 사용하는 방법을 알아봅니다.

이 튜토리얼에서는 Spring Boot 시작 가이드의 샘플 코드를 사용합니다.

학습할 내용

  • Spring Integration 및 Spring Cloud GCP를 사용하여 Google Cloud Pub/Sub로 앱 간에 메시지를 교환하는 방법

필요한 항목

  • Google Cloud Platform 프로젝트
  • 브라우저(Chrome, Firefox 등)
  • Vim, EMAC, Nano 등의 표준 Linux 텍스트 편집기에 관한 기본 지식

이 튜토리얼을 어떻게 사용하실 계획인가요?

읽기만 할 계획입니다 읽은 다음 연습 활동을 완료할 계획입니다

HTML/CSS 웹 앱 빌드 경험을 평가해 주세요.

초급 중급 고급

귀하의 Google Cloud Platform 서비스 사용 경험을 평가해 주세요.

<ph type="x-smartling-placeholder"></ph> 초보자 중급 숙련도

2. 설정 및 요구사항

자습형 환경 설정

  1. Google Cloud Console에 로그인하여 새 프로젝트를 만들거나 기존 프로젝트를 재사용합니다. 아직 Gmail이나 Google Workspace 계정이 없는 경우 계정을 만들어야 합니다.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • 프로젝트 이름은 이 프로젝트 참가자의 표시 이름입니다. 이는 Google API에서 사용하지 않는 문자열이며 언제든지 업데이트할 수 있습니다.
  • 프로젝트 ID는 모든 Google Cloud 프로젝트에서 고유하며, 변경할 수 없습니다(설정된 후에는 변경할 수 없음). Cloud 콘솔은 고유한 문자열을 자동으로 생성합니다. 일반적으로는 신경 쓰지 않아도 됩니다. 대부분의 Codelab에서는 프로젝트 ID (일반적으로 PROJECT_ID로 식별됨)를 참조해야 합니다. 생성된 ID가 마음에 들지 않으면 다른 임의 ID를 생성할 수 있습니다. 또는 직접 시도해 보고 사용 가능한지 확인할 수도 있습니다. 이 단계 이후에는 변경할 수 없으며 프로젝트 기간 동안 유지됩니다.
  • 참고로 세 번째 값은 일부 API에서 사용하는 프로젝트 번호입니다. 이 세 가지 값에 대한 자세한 내용은 문서를 참고하세요.
  1. 다음으로 Cloud 리소스/API를 사용하려면 Cloud 콘솔에서 결제를 사용 설정해야 합니다. 이 Codelab 실행에는 많은 비용이 들지 않습니다. 이 튜토리얼이 끝난 후에 요금이 청구되지 않도록 리소스를 종료하려면 만든 리소스 또는 프로젝트를 삭제하면 됩니다. Google Cloud 신규 사용자는 300달러(USD) 상당의 무료 체험판 프로그램에 참여할 수 있습니다.

Google Cloud Shell

Google Cloud를 노트북에서 원격으로 실행할 수도 있지만 이 Codelab에서는 Cloud에서 실행되는 명령줄 환경인 Google Cloud Shell을 사용합니다.

Cloud Shell 활성화

  1. Cloud Console에서 Cloud Shell 활성화853e55310c205094.png를 클릭합니다.

55efc1aaa7a4d3ad.png

Cloud Shell을 처음 시작하는 경우에는 무엇이 있는지 설명하는 중간 화면이 표시됩니다. 중간 화면이 표시되면 계속을 클릭합니다.

92662c6a846a5c.png

Cloud Shell을 프로비저닝하고 연결하는 데 몇 분 정도만 걸립니다.

9f0e51b578fecce5.png

가상 머신에는 필요한 개발 도구가 모두 들어 있습니다. 영구적인 5GB 홈 디렉터리를 제공하고 Google Cloud에서 실행되므로 네트워크 성능과 인증이 크게 개선됩니다. 이 Codelab에서 대부분의 작업은 브라우저를 사용하여 수행할 수 있습니다.

Cloud Shell에 연결되면 인증이 완료되었고 프로젝트가 자신의 프로젝트 ID로 설정된 것을 확인할 수 있습니다.

  1. Cloud Shell에서 다음 명령어를 실행하여 인증되었는지 확인합니다.
gcloud auth list

명령어 결과

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Cloud Shell에서 다음 명령어를 실행하여 gcloud 명령어가 프로젝트를 알고 있는지 확인합니다.
gcloud config list project

명령어 결과

[core]
project = <PROJECT_ID>

또는 다음 명령어로 설정할 수 있습니다.

gcloud config set project <PROJECT_ID>

명령어 결과

Updated property [core/project].

3. Pub/Sub 리소스 프로비저닝

Google Cloud Pub/Sub 주제 페이지로 이동합니다.

주제 만들기를 클릭합니다.

4c938409dc7169a6.png

주제 이름으로 exampleTopic를 입력하고 만들기를 클릭합니다.

e2daeec91537f672.png

주제를 만든 후 주제 페이지에 머무릅니다. 방금 만든 주제를 찾고 행 끝에 있는 3개의 수직 점을 누른 다음 새 구독을 클릭합니다.

975efa26e5054936.png

구독 이름 텍스트 상자에 exampleSubscription을 입력하고 만들기를 클릭합니다.

f7a91d9e1cb48009.png

4. Spring Boot 애플리케이션 초기화

Cloud Shell이 실행되면 명령줄을 사용하여 Spring Initializr로 두 개의 새로운 Spring Boot 애플리케이션을 생성할 수 있습니다.

$ curl https://start.spring.io/starter.tgz \
  -d bootVersion=3.0.5 \
  -d dependencies=web,integration,cloud-gcp-pubsub \
  -d type=maven-project \
  -d baseDir=spring-integration-sender | tar -xzvf -

$ curl https://start.spring.io/starter.tgz \
  -d bootVersion=3.0.5 \
  -d dependencies=web,integration,cloud-gcp-pubsub \
  -d type=maven-project \
  -d baseDir=spring-integration-receiver | tar -xzvf -

5. 메시지를 보낼 애플리케이션 만들기

이제 메시지 전송 앱을 만들어 보겠습니다. 발신 앱의 디렉터리로 변경합니다.

$ cd spring-integration-sender

앱이 채널에 메시지를 쓰도록 하려고 합니다. 메시지가 채널에 전송된 후 아웃바운드 채널 어댑터는 메시지를 일반 Spring 메시지에서 Google Cloud Pub/Sub 메시지로 변환하여 Google Cloud Pub/Sub 주제에 게시합니다.

앱이 채널에 쓰도록 하려면 Spring Integration 메시징 게이트웨이를 사용하면 됩니다. vim, emacs 또는 nano의 텍스트 편집기를 사용하여 DemoApplication 클래스 내에서 PubsubOutboundGateway 인터페이스를 선언합니다.

src/main/java/com/example/demo/DemoApplication.java

...
import org.springframework.integration.annotation.MessagingGateway;

@SpringBootApplication
public class DemoApplication {

  ...

  @MessagingGateway(defaultRequestChannel = "pubsubOutputChannel")
  public interface PubsubOutboundGateway {
    void sendToPubsub(String text);
  }
}

이제 채널에 메시지를 보내는 메커니즘이 있습니다. 그런데 메시지가 채널에 있으면 어디로 가나요?

채널의 새 메시지를 소비하고 Google Cloud Pub/Sub 주제에 게시하려면 아웃바운드 채널 어댑터가 필요합니다.

src/main/java/com/example/demo/DemoApplication.java

...
import com.google.cloud.spring.pubsub.core.PubSubTemplate;
import com.google.cloud.spring.pubsub.integration.outbound.PubSubMessageHandler;

import org.springframework.context.annotation.Bean;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.messaging.MessageHandler;

@SpringBootApplication
public class DemoApplication {

  ...

  @Bean
  @ServiceActivator(inputChannel = "pubsubOutputChannel")
  public MessageHandler messageSender(PubSubTemplate pubsubTemplate) {
    return new PubSubMessageHandler(pubsubTemplate, "exampleTopic");
  }
}

@ServiceActivator 주석을 사용하면 이 MessageHandlerinputChannel의 모든 새 메시지에 적용됩니다. 여기서는 아웃바운드 채널 어댑터인 PubSubMessageHandler를 호출하여 Google Cloud Pub/Sub의 exampleTopic 주제에 메시지를 게시합니다.

채널 어댑터가 준비되면 이제 PubsubOutboundGateway 객체를 자동으로 연결하고 이를 사용하여 채널에 메시지를 작성할 수 있습니다.

src/main/java/com/example/demo/DemoApplication.java

...
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.view.RedirectView;

@SpringBootApplication
public class DemoApplication {

  ...

  @Autowired
  private PubsubOutboundGateway messagingGateway;

  @PostMapping("/postMessage")
  public RedirectView postMessage(@RequestParam("message") String message) {
    this.messagingGateway.sendToPubsub(message);
    return new RedirectView("/");
  }
}

@PostMapping 주석으로 인해 이제 엔드포인트가 HTTP POST 요청을 수신 대기하지만 DemoApplication 클래스에 @RestController 주석을 추가하여 REST 컨트롤러로 표시합니다.

src/main/java/com/example/demo/DemoApplication.java

import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class DemoApplication {
  ...
}

JAVA_HOME이 올바른 버전으로 설정되어 있는지 확인합니다.

export JAVA_HOME=/usr/lib/jvm/java-1.17.0-openjdk-amd64

발신기 앱을 실행합니다.

# Set the Project ID in environmental variable
$ export GOOGLE_CLOUD_PROJECT=`gcloud config list --format 'value(core.project)'`

$ ./mvnw spring-boot:run

앱은 포트 8080과 엔드포인트 /postMessage에서 메시지가 포함된 POST 요청을 수신 대기하고 있지만 나중에 살펴볼 예정입니다.

6. 메시지를 수신할 애플리케이션 만들기

Google Cloud Pub/Sub를 통해 메시지를 전송하는 앱을 만들었습니다. 이제 이러한 메시지를 수신하고 처리하는 다른 앱을 만들어 보겠습니다.

+를 클릭하여 새 Cloud Shell 세션을 엽니다.

9799bee5fea95aa6.png

그런 다음 새 Cloud Shell 세션에서 디렉터리를 수신자 앱의 디렉터리로 변경합니다.

$ cd spring-integration-receiver

이전 앱에서는 메시지 게이트웨이 선언으로 발신 채널이 생성되었습니다. 메시지를 수신하는 데 메시지 게이트웨이를 사용하지 않으므로 수신 메시지가 도착할 자체 MessageChannel를 선언해야 합니다.

src/main/java/com/example/demo/DemoApplication.java

...
import org.springframework.context.annotation.Bean;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.messaging.MessageChannel;

@SpringBootApplication
public class DemoApplication {

  ...

  @Bean
  public MessageChannel pubsubInputChannel() {
    return new DirectChannel();
  }
}

Google Cloud Pub/Sub에서 메시지를 수신하고 pubsubInputChannel에 릴레이하려면 인바운드 채널 어댑터가 필요합니다.

src/main/java/com/example/demo/DemoApplication.java

...
import com.google.cloud.spring.pubsub.core.PubSubTemplate;
import com.google.cloud.spring.pubsub.integration.inbound.PubSubInboundChannelAdapter;

import org.springframework.beans.factory.annotation.Qualifier;

@SpringBootApplication
public class DemoApplication {

  ...

  @Bean
  public PubSubInboundChannelAdapter messageChannelAdapter(
      @Qualifier("pubsubInputChannel") MessageChannel inputChannel,
      PubSubTemplate pubSubTemplate) {
    PubSubInboundChannelAdapter adapter =
        new PubSubInboundChannelAdapter(pubSubTemplate, "exampleSubscription");
    adapter.setOutputChannel(inputChannel);

    return adapter;
  }
}

이 어댑터는 자체적으로 pubsubInputChannel에 바인딩되고 Google Cloud Pub/Sub exampleSubscription 구독에서 새 메시지를 리슨합니다.

받은 메시지를 게시하는 채널이 있는데 이러한 메시지는 어떻게 처리해야 할까요?

새 메시지가 pubsubInputChannel에 도착하면 트리거되는 @ServiceActivator를 사용하여 처리하겠습니다. 이 경우에는 메시지 페이로드만 기록합니다.

src/main/java/com/example/demo/DemoApplication.java

...
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.integration.annotation.ServiceActivator;

@SpringBootApplication
public class DemoApplication {

  ...

  private static final Log LOGGER = LogFactory.getLog(DemoApplication.class);

  @ServiceActivator(inputChannel = "pubsubInputChannel")
  public void messageReceiver(String payload) {
    LOGGER.info("Message arrived! Payload: " + payload);
  }
}

JAVA_HOME이 올바른 버전으로 설정되어 있는지 확인합니다.

export JAVA_HOME=/usr/lib/jvm/java-1.17.0-openjdk-amd64

수신기 앱을 실행합니다.

$ ./mvnw spring-boot:run -Dspring-boot.run.jvmArguments="-Dserver.port=8081"

이제 발신자 앱에 보내는 모든 메시지가 수신자 앱에 기록됩니다. 이를 테스트하려면 새 Cloud Shell 세션을 열고 발신기 앱에 HTTP POST 요청을 전송합니다.

$ curl --data "message=Hello world!" localhost:8080/postMessage

그런 다음 보낸 메시지가 수신자 앱에 기록되었는지 확인합니다.

INFO: Message arrived! Payload: Hello world!

7. 삭제

이 연습의 일부로 만든 구독 및 주제를 삭제합니다.

$ gcloud pubsub subscriptions delete exampleSubscription
$ gcloud pubsub topics delete exampleTopic

8. 요약

Google Cloud Pub/Sub용 Spring Integration 채널 어댑터를 사용하는 Spring Boot 앱 2개를 설정합니다. Google Cloud Pub/Sub API와 상호작용하지 않고 서로 간에 메시지를 교환합니다.

9. 축하합니다.

지금까지 Google Cloud Pub/Sub용 Spring Integration 채널 어댑터를 사용하는 방법을 알아봤습니다.

자세히 알아보기

라이선스

이 작업물은 Creative Commons Attribution 2.0 일반 라이선스에 따라 사용이 허가되었습니다.