Spring Integration은 잘 알려진 Enterprise Integration Pattern을 지원하기 위해서 Spring 의 프로그래밍 모델을 messaging domain 까지 확장한 것
Enterprise Integration Pattern
- Patterns and Best Practices for Asynchronous Messaging
- Messaging Patterns in Today's World: Microservices and Serverless
- 비지니스 로직이 언제 실행되어야 하는지, 응답이 어디로 보내져야 하는지와 같은 내용들에 대해 Inversion of Control이 적용되면서 메시지 주도 아키텍처를 지원
- 메시지의 라우팅과 변환을 지원함 → different transport 와 서로 다른 데이터 형식이 테스트 용이성을 떨어뜨리지 않으면서 통합 가능함. 즉, 메시징과 통합에 대한 관심사를 프레임워크가 관리해줌
- 비지니스 컴포넌트들은 인프라에서부터 독립되어서 개발자들은 복잡한 통합과 관련된 작업을 할 필요가 없어지게 됨
- Spring Integration의 주요 목적은 지속가능하고 테스트 가능한 코드의 핵심인 관심사 분리를 유지하면서 Enterprise integration solution을 구현하기 위한 간단한 모델을 제공하는 것임
- Messaging 과 Integration concern이 Spring Integration Framework에 의해서 다루어짐. 그래서 개발자는 비지니스 로직 구현만 하면 되고 복잡한 integration 책임을 Spring Integration framework에게 넘길 수 있음
Goals and Principles
목표
- 복잡한 Enterprise integration solution을 구현하기 위해 간단한 모델을 제공해줌
- 스프링 기반의 어플리케이션에서 비동기, 메시지 주도 작업을 용이하게 해줌
- 기존의 스프링 유저에게 직관적이고 점진적인 도입을 촉진시켜줌
원칙
- 컴포넌트들은 서로 유연하게 결합되어 있어 modularity와 testability를 저해하지 않아야 함
- 프레임워크는 비지니스 로직과 통합 로직 사이의 관심사 분리를 철저하게 해야 함
- 재사용성과 이식성을 향상시키기 위해 확장 포인트는 본질적으로 추상적이어야 함(그러나 잘 정의된 경계 안에서)
Main Components
- 수직적 관점에서, 계층적 아키텍처는 관심사 분리를 촉진시키고, 계층 사이에서 인터페이스 기반의 계약으로 인해 느슨한 결합을 증진 시켜줌 ⇒ 스프링 기반의 어플리케이션은 전통적으로 이러한 방식으로 디자인 됨
- 메시지 주도 아키텍처는 동일한 목표를 유지하면서 수평적 관점을 추가시켜 줌
- 계층적 아키텍처가 극단적으로 generic하고 abstract한 패러다임인 것과 같이 메시징 시스템은 비슷한 추상화인 “
pipes-and-filters
” 모델을 따름 - filters : 메시지를 생산하고 소비할 수 있는 임의의 컴포넌트
- pipes : 메시지를 필터 사이에서 운송하는 역할을 함. 그리하여 컴포넌트 그 자체는 느슨한 결합(loosely-coupled)을 유지할 수 있게 해줌
- 이 두개의 고수준의 패러다임은 상호 배타적이지 않음
- pipe를 지원하는 기반 메시징 인프라는 레이어 안에 캡슐화되어 있어야 함. 그리고 각각의 레이어는
interface
로 서로 계약을 함 - 마찬가지로 filters는 논리적으로 어플리케이션의 서비스 레이어보다 위에 있는 레이어 안에서 관리되어야 함 → 그리하여 서비스 레이어와
interface
를 통하여 상호작용을 하게 됨
Message
Java object
와 프레임워크에 의해 사용되는 meta data
를 포함하는 wrapper
라고 생각하면 됨
payload
와header
로 구성되어 있음
payload
는 어떠한 타입도 가능하고,header
는 ID, timestamp, correlation ID, return address와 같은 일반적으로 필요한 정보들을 갖고 있음
- 예를 들어 전달되어 온 파일로 부터 메시지를 만들 때, 파일의 이름은 다운스트림에서 사용될 수도 있기 때문에 헤더에 포함되어야 할 수 있음
- 마찬가지로, 메시지의 내용은 외부의 메일 아답터로부터 전송될 수 있고, 여러 다양한 프로퍼티들(to, from, cc, subject, and others)이 upstream component에서 메시지 헤더 값으로 구성될 수 있음
Message Channel (pipe
)

- 메시지 채널은
pipes-and-filters
아키텍쳐에서pipe
에 해당하는 컴포넌트임
- Producer는 메시지를 채널에 보내고 Consumer는 메시지를 채널에서 받음 ⇒ 메시지 채널이 메시징 컴포넌트들을 decouple 시키고 message의 intercept, monitoring을 할 수 있음
- 메시지 채널은 point-to-point(consumer가 1명)일 수도, publich-subscribe(broadcast 방식. consumer가 여러 명) 일수도 있음
- Spring Integration에서
pollable channel
은 Message의 버퍼링을 큐 안에서 진행할 수 있음 - 버퍼링의 장점은 인바운드 메시지의 스로틀링을 가능케 하여 consumer의 오버로딩을 방지할 수 있다는 점임(하나의 큐로만 작업들을 받게 되기 때문에 감당 불가능한 만큼의 작업이 들어오는 것을 방지할 수 있음)
- 그러나 이름에서 알 수 있듯이, 이는 복잡성을 더하게 됨. 왜냐하면 consumer가 poller가 구성된 채널에서만 메시지를 받을 수 있기 때문임.
- 반면, subscribable channel에 연결된 consumer는 단순한 메시지 주도 방식임
Message Endpoint ( filter
)
- Spring Integration을 사용하는 이유는 IoC를 위함이고, 그럼으로써 producer와 consumer를 직접 구현할 필요가 없어지는 것임. 그리고 message의 빌드와 message channel에 전송, 수령하는 operation도 굳이 할 필요 없음
- 대신 domain object에 집중하여 로직을 구성한 후 configuration을 통해서 messaging infrastructure에 연결하는 데 이 연결을 담당하는 컴포넌트가
message endpoint
임 - 이 말이, 직접 어플리케이션 코드를 작성해서 연결을 해야 한다는 것은 아님. 실제적으로 쓰이는 어떠한 enterprise integration solution도 통합을 위한 명시적인 코드(routing & transformation)들을 필요로 함
- 어플리케이션 코드는 메시지 오브젝트와 메시지 채널에 대해 전혀 몰라야 함. (MVC 패러다임과 비슷함. Controller가 http rqeuet를 핸들하는 것을 전혀 신경 안 쓰듯이)
pipes-and-filters
아키텍처에서filter
의 역할을 함
- controller가 HTTP
request
를url pattern
으로 매칭하여 받듯이,message endpoint
는message channel
에 매핑됨
Message Endpoints
Message Transformer
- 메시지의 내용과 구조를 변환하고 변경된 메시지를 반환하는 역할을 담당함
Message Filter
- 메시지가 아웃풋 채널로 전달되어야 하는지 말아야 하는지를 결정함. 이를 위해 간단한 boolean test method가 필요
- 메시지가 accepted되면 아웃풋 채널로 보내지게 됨. 그렇지 않으면 버려지게 됨(또는 더 엄격한 구현에서는 예외를 던질 수도 있음)
- 메시지 필터는 pub-sub channel과 함게 주로 자주 사용됨 (예로, 다수의 consumer가 같은 메시지를 받았을 때, 필터를 이용하여 처리할 메시지의 집합을 걸러낼 수 있음)
pipe-and-filter 아키텍처 패턴에서의 filter와 이 필터를 헷갈리지 말기. pipe-and-filter 개념에서의
filter
는 Spring Integration에서 Message endpoint
의 개념에 더 가까움Message Router

- 어떤 채널에서 해당 메시지를 받아야 할지를 결정하는 역할을 담당함
- 보통, 해당 결정은 메시지의 content나 header를 기반으로 내려지게 됨
Splitter
- message를 인풋채널에서 받아서 해당 메시지를 다수의 메시지로 분리하여 각각을 해당하는 아웃풋 채널로 보내는 역할
- 이 컴포넌트는 주로 복합적인 payload object를 여러개의 메시지 그룹으로 나누어서 전송할 때 쓰이게 됨
Aggregator
- Splitter의 반대 역할로 다수의 메시지를 받아서 하나의 메시지로 합치는 역할을 수행함
Service Activator

- 서비스 인스턴스를 메시징 시스템에 연결하는 generic endpoint임
- 인풋 메시지 채널이 꼭 구성되어야 하고, 호출되는 서비스 메서드가 반환값이 있다면 아웃풋 메시지 채널 또한도 제공되어야 함
- Service activator는 요청 메시지를 처리하기 위해 서비스 오브젝트의 연산을 호출하게 되고 요청 메시지의 본문을 빼내어 변환하는 과정을 진행함
- 서비스 오브젝트의 메서드가 값을 반환한다면 해당 값은 필요하다면 응답 메시지로 변환 되어야 함(그것이 이미 message type 이 아니라면)
- 아웃풋 채널이 구성되어 있지 않다면 메시지에 명시되어 있는 return address로 응답이 보내지게 됨
Channel Adapter
- 메시지 채널을 다른 시스템 혹은 transport로 연결짓는 엔드포인트임
- 보통, 채널 아답터는
message
와다른 어떠한 오브젝트 혹은 리소스
(file, HTTP Request, JMS message, and others) 사이에서의 매핑을 수행함
Messaging Gateway
- Spring Integration에 의해서 제공되는 메시징 api를 숨겨주는 역할을 함. 어플리케이션 비즈니스 로직 코드가 Spring Integration API를 모르도록 해줌. generic Gateway를 사용함으로써 사용자의 코드는 간단한 인터페이스로만 소통함
- 즉, 하는 역할은 message를 보내주는 역할.
Configuration
@IntegrationComponentScan
: classpath scanning을 하지만 Spring Integration과 관련된 컴포넌트와 어노테이션만 스캔을 진행함. 일반@ComponentScan
으로는 안되는 곳까지