Back-end/Spring

[Spring] 멀티 MQ 리스너 개발 내용

shoney9254 2023. 12. 20. 09:30
반응형

멀티 MQ 리스너 개발 내용

MQ 서버 추가 및 큐 이름 추가 되는 경우 아래 개발 내용 참조해서 추가하면 됩니다.

단일 MQ 서버 연결에서 다중 MQ 서버로 변경하는 내용을 정리했습니다.

 


 

1. MQ application.yml

profile에 맞는 설정을 해야 합니다. 설명을 위해 default profile로 설명 드립니다. (dev, prd는 서버 주소에 맞게 모두 설정해야합니다.)

 

1-1. MQ 서버 주소를 yml 설정

ibm:
  mq:
    serverA:
      hostName: mqa.server.com
      port: 1961
      queueManager: ABT.PSS
      channel: CLIENT.TO.QNAME
      userName: mpns
      password:
      appName:  QNAME
      retryMaxInterval: 300000
      sleepTime: 2000
    serverB:
      hostName: mqb.server.com
      port: 1962
      queueManager: A1T.PSS
      channel: CLIENT.TO.QNAME
      userName: mpns
      password:
      appName:  QNAME
      retryMaxInterval: 300000
      sleepTime: 2000
  • serverA와 serverB의 구분이 필요하기 때문에 serverA, serverB 레이어 추가
  • MQ 서버안에 여러 큐가 존재합니다. 큐 이름 설정은 Listener에서 설정하면 됩니다. (3.MQ JmsListener 참조)

 

1-2. Props

props는 yml에서 설정한 내용들을 객체로 사용하기 위해서 만들어줍니다.

불필요하면 사용하지 않아도 되지만, Map과 객체를 사용해서 휴먼 에러를 줄일 수 있습니다.

(props를 사용하지 않을 경우에는 @Value로 yml 설정 내용 사용)

 

1-2-1. MqPropsMap

@Component
@Data
@ConfigurationProperties(prefix = "ibm")
public class MqPropsMap {
    private Map<String, MqProps> mq;
}
  • @ConfigurationProperties 를 사용해서 MqProps를 Map으로 관리합니다.
  • 단일 서버일 경우에는 MqProps를 바로 만들어도 됩니다.

 

1-2-2. MqProps

@Data
public class MqProps {
   private String hostName;
    private int port;
    private String queueManager;
    private String channel;
    private String userName;
    private String password;
    private String appName;
    private long retryMaxInterval;
    private long sleepTime;
}
  • MqProps는 MQQueueConnectionFactory 에서 설정으로 사용할 대상들을 변수 관리합니다.
  • 단일 서버일 경우에는 MqProps클래스에 @ConfigurationProperties 사용해야합니다.

 

 


 

2. MQ Config

아래 두가지 팩토리 클래스로 MQ 서버 연결을 할 수 있습니다.

MQQueueConnectionFactory : MQ 서버 주소 및 옵션 설정

JmsListenerContainerFactory : ConnectionFactory 연결

 

2-1. MQQueueConnectionFactory

@Bean
public MQQueueConnectionFactory serverAMqQueueConnectionFactory() {
    MQQueueConnectionFactory connectionFactory = createConnectFactory(MqKeys.SERVER_A);
    return connectionFactory;
}
  • MQ Config 설정을 위해 위 내용을 Bean에 등록합니다.
  • createConnectFactory은 private 메서드로 아래 내용에서 추가 설명하도록 하겠습니다.
  • 휴먼 에러 및 관리를 위해 MqKeys는 Enum으로 관리합니다.

 

2-2. MQQueueConnectionFactory 내부의 createConnectFactory private 메서드

private MQQueueConnectionFactory createConnectFactory(MqKeys keys) {
    MQQueueConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();
    if (mqPropsMap.getMq().containsKey(keys.getKeyName())) {
        MqProps mqProps = mqPropsMap.getMq().get(keys.getKeyName());
        mqQueueConnectionFactory.setHostName(mqProps.getHostName());
        try {
            mqQueueConnectionFactory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
            mqQueueConnectionFactory.setChannel(mqProps.getChannel());
            mqQueueConnectionFactory.setPort(mqProps.getPort());
            mqQueueConnectionFactory.setQueueManager(mqProps.getQueueManager());
            mqQueueConnectionFactory.setAppName(mqProps.getAppName());
            mqQueueConnectionFactory.setClientReconnectOptions(WMQConstants.WMQ_CLIENT_RECONNECT_Q_MGR);
            mqQueueConnectionFactory.setClientReconnectTimeout(43200);        // 12 hours
        } catch (JMSException e) {
log.error("[MQQueueConnectionFactory JMSException - {}] : {}", keys.getKeyName(), e.getMessage());
        }
    }
    return mqQueueConnectionFactory;
}
  • 1-2에서 만든 MqPropsMap를 사용합니다. Map에서 Props를 꺼내고, Props 내의 설정 정보를 꺼내와서 MQQueueConnectionFactory에 설정을 해줍니다.

 

2-3. JmsListenerContainerFactory

@Bean
public JmsListenerContainerFactory<?> jmsServerAListenerContainerFactory(@Qualifier("serverAMqQueueConnectionFactory") MQConnectionFactory connectionFactory) {
    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    factory.setConnectionFactory(connectionFactory);
    return factory;
}
  • @Qualifier로 빈 객체명을 정확하게 작성해야지 원하는 서버와 연결이 가능합니다. (MQ 서버가 단일 서버일 경우에는 사용하지 않아도 됩니다.)
  • setConnectionFactory를 사용해서 JmsListenerContainerFactory 와 MQQueueConnectionFactory간의 연결을 해줍니다.

 

 


 

3. MQ JmsListener

다대일로 구현하기 위해서는 @JmsListener 어노테이션을 사용해서 어떤 서버의 어떤 큐로 부터 메세지를 받을 건지 지정할 수 있습니다.

@JmsListener(destination = "SERVER_A_MQNAME_1", containerFactory = "jmsServerAListenerContainerFactory")
public void onMessageA1(Message message) {
	// 로직 구현 
}

@JmsListener(destination = "SERVER_A_MQNAME_2", containerFactory = "jmsServerAListenerContainerFactory")
public void onMessageA2(Message message) {
	// 로직 구현 
}

@JmsListener(destination = "SERVER_B_MQNAME_1", containerFactory = "jmsServerBListenerContainerFactory")
public void onMessageB1(Message message) {
	// 로직 구현 
}

이 처럼 사용하게 되면, Controller의 메서드와 비슷한 포맷으로 사용할 수 있습니다.

  • destination : 큐 이름을 작성하면, 해당 큐에서 메세지를 가져옵니다. (큐 이름 기준)
  • containerFactory : ContainerFactory 빈 객체 명을 작성 (MQ 서버 ContainerFactory 기준)

※ 하나의 MQ 서버에 여러 이름의 큐가 들어가 있을 수 있다.

반응형