Spring 통합 JMS(3) - MessageConverter 소개

16773 단어

메시지 변환기 MessageConverter


 
MessageConverter의 역할은 주로 두 가지가 있는데 하나는 우리의 비표준화 Message 대상을 우리의 목표 Message 대상으로 전환시킬 수 있는데 이것은 주로 메시지를 보낼 때 사용된다.다른 한편, 우리의 메시지 대상을 대응하는 목표 대상으로 전환할 수 있는데 이것은 주로 메시지를 받을 때 사용된다.
다음에 우리는 대상 메시지를 보내는 것을 예로 들자. 만약에 우리가 이런 수요를 가지고 있다고 가정하자. 우리 플랫폼에는 메일을 보내는 기능이 있는데 발송할 때 우리는 우리의 관련 정보를 하나의 JMS 메시지로 봉한 다음에 JMS를 이용하여 발송하고 대응하는 메시지 감청기가 수신한 정보를 처리할 때만 진정으로 메시지를 발송한다.
Email 객체가 있다고 가정해 봅시다.
public class Email implements Serializable {
 
    private static final long serialVersionUID = -658250125732806493L;
 
    private String receiver;
    private String title;
    private String content;
 
    public Email(String receiver, String title, String content) {
        this.receiver = receiver;
        this.title = title;
        this.content = content;
    }
 
    public String getReceiver() {
        return receiver;
    }
 
    public void setReceiver(String receiver) {
        this.receiver = receiver;
    }
 
    public String getTitle() {
        return title;
    }
 
    public void setTitle(String title) {
        this.title = title;
    }
 
    public String getContent() {
        return content;
    }
 
    public void setContent(String content) {
        this.content = content;
    }
 
    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("Email [receiver=").append(receiver).append(", title=")
                .append(title).append(", content=").append(content).append("]");
        return builder.toString();
    }
    
}
 
이 이메일 대상에는 간단한 수신자 이메일 주소, 메일 테마, 메일 내용이 포함되어 있습니다.우리는 이 대상을 ObjectMessage로 봉하여 발송합니다.코드는 다음과 같습니다.
public class ProducerServiceImpl implements ProducerService {
 
    @Autowired
    private JmsTemplate jmsTemplate;    

    public void sendMessage(Destination destination, final Serializable obj) {
        jmsTemplate.send(destination, new MessageCreator() {
 
            public Message createMessage(Session session) throws JMSException {
                ObjectMessage objMessage = session.createObjectMessage(obj);
                return objMessage;
            }
            
        });
    }
 
}

이것은 Message Converter를 사용하지 않았을 때 new의 Message Creator 인터페이스 대상이 필요할 때 추상적인 방법인create Message 내부에서session을 사용하여 대응하는 메시지를 만들어야 합니다.Message Converter를 사용할 때 JmsTemplate를 사용하여 메시지를 보낼 때 그에 대응하는 convertAndSend 방법을 호출하면 됩니다.예:
    public void sendMessage(Destination destination, final Serializable obj) {
        // MessageConverter 
        /*jmsTemplate.send(destination, new MessageCreator() {
 
            public Message createMessage(Session session) throws JMSException {
                ObjectMessage objMessage = session.createObjectMessage(obj);
                return objMessage;
            }
            
        });*/
        // MessageConverter 
        jmsTemplate.convertAndSend(destination, obj);
    }

이렇게 하면 JmsTemplate는 내부에서 예정된 MessageConverter를 호출하여 우리의 메시지 대상을 변환한 다음에 발송합니다.
이럴 때 우리는 우리의 Message Converter를 정의해야 한다.자신의 Message Converter를 정의하는 것은 매우 간단하다. Spring이 우리에게 제공하는 Message Converter 인터페이스를 실현하기만 하면 된다.먼저 MessageConverter 인터페이스의 정의를 살펴보겠습니다.
public interface MessageConverter {
 
    Message toMessage(Object object, Session session) throws JMSException, MessageConversionException;
 
    Object fromMessage(Message message) throws JMSException, MessageConversionException;
 
}

그 중에서 두 가지 방법이 정의되어 있음을 알 수 있다. fromMessage와 toMessage이다. fromMessage는 하나의 JMSMessage를 대응하는 자바 대상으로 전환하는 데 사용되고, toMessage 방법은 하나의 자바 대상을 대응하는 JMSMessage로 전환하는 데 사용된다.위에서 보내야 할 대상이 하나의 이메일 대상이라는 것을 알고 있기 때문에 여기서 우리는 간단히 이메일 메시지Converter를 정의하여 이메일 대상과 대응하는 ObjectMessage를 변환하는데 그 코드는 다음과 같다.
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.ObjectMessage;
import javax.jms.Session;
 
import org.springframework.jms.support.converter.MessageConversionException;
import org.springframework.jms.support.converter.MessageConverter;
 
public class EmailMessageConverter implements MessageConverter {
 
    public Message toMessage(Object object, Session session)
            throws JMSException, MessageConversionException {
        return session.createObjectMessage((Serializable) object);
    }
 
    public Object fromMessage(Message message) throws JMSException,
            MessageConversionException {
        ObjectMessage objMessage = (ObjectMessage) message;
        return objMessage.getObject();
    }
 
}

 
이렇게 하면 JmsTemplate의convertAndSend 방법을 이용하여 이메일 대상을 보낼 때 대응하는 이메일 대상을 매개 변수로 우리가 정의한 이메일MessageConverter의 toMessage 방법을 호출합니다.
Email Message Converter를 정의한 후 Email 대상을 보내는 JmsTemplate 대상의 메시지 Converter를 Email Message Converter로 지정해야 합니다. Spring 프로필에서 JmsTemplatebean을 정의할 때 지정합니다.
    <!-- Spring JMS , 、  -->
    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <!--  connectionFactory Spring ConnectionFactory  -->
        <property name="connectionFactory" ref="connectionFactory"/>
        <!--   -->
        <property name="messageConverter" ref="emailMessageConverter"/>
    </bean>
    <!--   -->
    <bean id="emailMessageConverter" class="com.tiantian.springintejms.converter.EmailMessageConverter"/>

   
이렇게 MessageConverter가 정의되어 있고 사용할 수도 있습니다. 그런 다음 테스트 코드를 다음과 같이 정의합니다.
    @Test
    public void testObjectMessage() {
        Email email = new Email("[email protected]", " ", " ");
        producerService.sendMessage(destination, email);
    }

위 destination에 해당하는 수신 처리에 대한 MessageListener 방법은 다음과 같습니다.
public class ConsumerMessageListener implements MessageListener {
 
    public void onMessage(Message message) {
        
        if (message instanceof ObjectMessage) {
            ObjectMessage objMessage = (ObjectMessage) message;
            try {
                Object obj = objMessage.getObject();
                Email email = (Email) obj;
                System.out.println(" ObjectMessage, Email 。");
                System.out.println(email);
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    }
 
}

앞서 말했듯이MessageConverter는 자바 대상을 대응하는 JmsMessage로 바꾸는 것 외에 JmsMessage를 대응하는 자바 대상으로 바꾸는 두 가지 기능이 있다.위의 메시지 감청기가 메시지를 받을 때 받는 것은 바로 Jms Message입니다. 만약에 우리가 Message Converter를 이용하여 대응하는 자바 대상으로 바꾸려면 그 안에 대응하는 Message Converter를 주입한 다음에 안에서 수동으로 호출할 수 밖에 없습니다. 예를 들어 다음과 같습니다.
public class ConsumerMessageListener implements MessageListener {
 
    private MessageConverter messageConverter;
    
    public void onMessage(Message message) {
        
        if (message instanceof ObjectMessage) {
            ObjectMessage objMessage = (ObjectMessage) message;
            try {
                /*Object obj = objMessage.getObject();
                Email email = (Email) obj;*/
                Email email = (Email) messageConverter.fromMessage(objMessage);
                System.out.println(" ObjectMessage, Email 。");
                System.out.println(email);
            } catch (JMSException e) {
                e.printStackTrace();
            }
            
        }
    }
 
    public MessageConverter getMessageConverter() {
        return messageConverter;
    }
 
    public void setMessageConverter(MessageConverter messageConverter) {
        this.messageConverter = messageConverter;
    }
 
}

Message Listener Adapter를 메시지 감청기로 사용할 때, Spring은 받은 메시지를 처리할 때 자동으로 Message Converter를 사용해서 변환한 자바 대상을 매개 변수로 지정한 메시지 처리 방법을 호출할 수 있습니다.여기서 우리는 앞의 Message Listener Adapter를 설명할 때 정의한 Message Listener Adapter를 가지고 와서 테스트를 해보자. 우리는 Message Converter가 우리가 정의한 Email Message Converter를 지정한다.
    <!--   -->
    <bean id="messageListenerAdapter" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
        <property name="delegate">
            <bean class="com.tiantian.springintejms.listener.ConsumerListener"/>
        </property>
        <property name="defaultListenerMethod" value="receiveMessage"/>
        <property name="messageConverter" ref="emailMessageConverter"/>
    </bean>
    <!--   -->
    <bean id="messageListenerAdapterContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactory"/>
        <property name="destination" ref="adapterQueue"/>
        <property name="messageListener" ref="messageListenerAdapter"/><!--  MessageListenerAdapter  -->
    </bean>

 
그런 다음 수신된 메시지를 처리하는 데 실제로 사용되는 ConsumerListener에 receiveMessage 메서드를 추가합니다. 추가된 코드는 다음과 같습니다.
public class ConsumerListener {
 
    public void receiveMessage(String message) {
        System.out.println("ConsumerListener receiveMessage , :" + message);
    }
    
    public void receiveMessage(Email email) {
        System.out.println(" Email ObjectMessage。");
        System.out.println(email);
    }
    
}

 
그런 다음 다음과 같은 테스트 코드를 정의합니다.
    @Test
    public void testObjectMessage() {
        Email email = new Email("[email protected]", " ", " ");
        producerService.sendMessage(adapterQueue, email);
    }

Message Listener Adapter에 Message Converter를 지정했고 Email Message Converter이기 때문에 Message Listener Adapter가 메시지를 받은 후에 우리가 지정한 Message Converter의from Message 방법을 사용해서 자바 대상으로 변환합니다. 정의에 따라 여기에 Email 대상으로 변환됩니다.그리고 이 Email 대상을 매개 변수로 호출합니다.default Listener Method 속성을 통해 지정한 기본 프로세서 방법입니다. 정의에 따라 여기는receive Message 방법입니다. 그러나 Consumer Listener에서 우리는 모두 두 개의receive Message 방법을 정의했습니다. 변환된 Email 대상을 매개 변수로 호출하는 방법이기 때문입니다.그래서 여기 호출된 것은 파라미터 형식이 Email인 Receive Message 방법일 것입니다.위의 테스트 코드가 실행되면 다음과 같은 결과가 출력됩니다.
 
여기까지만 말하면 독자들이 의문을 품게 될 것이다. 우리가 이전에 Message Listener Adapter를 설명할 때 대응하는 Message Converter를 지정하지 않고 Text Message를 보냈는데 Spring은 그것을 하나의 String 대상으로 전환하고Consumer Listener 매개 변수 유형을 String으로 하는receive Message 방법을 사용했는가?그럼 이 Message Converter가 Message Listener Adapter에서 메시지를 받을 때도 소용없잖아.
      
Message Listener Adapter를 사용할 때 초기화, 즉 구조 방법을 호출할 때, 이것은 기본적으로 new의 스프링이 이미 실현한 Message Converter인 Simple Message Converter를 기본으로 합니다.이것이 바로 우리가 Message Listener Adapter를 사용할 때 Message Converter를 지정하지 않아도 메시지가 대응하는 자바 대상으로 전환되는 이유입니다.따라서 기본적으로 우리가 Message Listener Adapter를 사용할 때 그에 대응하는 Message Listener의 프로세서 방법 매개 변수 형식은 일반적인 자바 대상이어야 하며 대응하는 Jms Message 대상이 되어서는 안 된다.
       
만약에 우리가 Jms Message를 처리할 때 Message Listener Adapter를 사용하고 싶고 Message Converter를 통해 전환된 Message가 아닌 가장 원시적인 Message를 처리하고 싶다면 어떻게 해야 합니까?이럴 때는 Message Listener Adapter를 정의할 때 Message Converter를 비워 두면 됩니다.
    <!--   -->
    <bean id="messageListenerAdapter" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
        <property name="delegate">
            <bean class="com.tiantian.springintejms.listener.ConsumerListener"/>
        </property>
        <property name="defaultListenerMethod" value="receiveMessage"/>
        <property name="messageConverter">
            <null/>
        </property>
    </bean>

그러면 이때 우리의 실제 Message Listener의 프로세서 방법 매개 변수 유형은 Jms Message 또는 대응하는 Jms Message 하위 유형이어야 한다. 그렇지 않으면 대응하는 처리 방법을 호출하지 못할 것이다.여기에 ObjectMessage를 보냈기 때문에 해당하는 매개 변수 형식이 ObjectMessage인receiveMessage 방법을 추가합니다.
    public void receiveMessage(ObjectMessage message) throws JMSException {
        System.out.println(message.getObject());
    }

방금 Spring이 우리에게 간단한 Message Converter, 즉 org를 실현해 주었다고 말했다.springframework.jms.support.converter.Simple Message Converter, 사실 Spring은 JmsTemplate를 초기화할 때도 대응하는 Message Converter를 Simple Message Converter로 지정했기 때문에 우리가 평소에 특별한 요구가 없을 때 JmsTemplate의 convert And Send 시리즈 방법을 직접 사용하여 메시지를 보낼 수 있기 때문에send 방법을 호출할 때 new Message Creator를 사용하여 해당하는 Message 생성을 할 필요가 없다.
여기에 Simple Message Converter의 정의를 살펴보겠습니다. 만약 그것이 당신의 요구를 충족시키지 못한다고 생각한다면, 우리는 그 안의 일부 방법을 다시 쓰거나, 자신의 Message Converter를 완전히 실현할 수 있습니다.
public class SimpleMessageConverter implements MessageConverter {
 
    public Message toMessage(Object object, Session session) throws JMSException, MessageConversionException {
        if (object instanceof Message) {
            return (Message) object;
        }
        else if (object instanceof String) {
            return createMessageForString((String) object, session);
        }
        else if (object instanceof byte[]) {
            return createMessageForByteArray((byte[]) object, session);
        }
        else if (object instanceof Map) {
            return createMessageForMap((Map) object, session);
        }
        else if (object instanceof Serializable) {
            return createMessageForSerializable(((Serializable) object), session);
        }

        else {
            throw new MessageConversionException("Cannot convert object of type [" +
                    ObjectUtils.nullSafeClassName(object) + "] to JMS message. Supported message " +
                    "payloads are: String, byte array, Map<String,?>, Serializable object.");
        }
    }
 
    public Object fromMessage(Message message) throws JMSException, MessageConversionException {
        if (message instanceof TextMessage) {
            return extractStringFromMessage((TextMessage) message);
        }
        else if (message instanceof BytesMessage) {
            return extractByteArrayFromMessage((BytesMessage) message);
        }
        else if (message instanceof MapMessage) {
            return extractMapFromMessage((MapMessage) message);
        }
        else if (message instanceof ObjectMessage) {
            return extractSerializableFromMessage((ObjectMessage) message);
        }
        else {
            return message;
        }
    }
 
    protected TextMessage createMessageForString(String text, Session session) throws JMSException {
        return session.createTextMessage(text);
    }
 
    protected BytesMessage createMessageForByteArray(byte[] bytes, Session session) throws JMSException {
        BytesMessage message = session.createBytesMessage();
        message.writeBytes(bytes);
        return message;
    }
 
    protected MapMessage createMessageForMap(Map<?, ?> map, Session session) throws JMSException {
        MapMessage message = session.createMapMessage();
        for (Map.Entry entry : map.entrySet()) {
            if (!(entry.getKey() instanceof String)) {
                throw new MessageConversionException("Cannot convert non-String key of type [" +
                        ObjectUtils.nullSafeClassName(entry.getKey()) + "] to JMS MapMessage entry");
            }
            message.setObject((String) entry.getKey(), entry.getValue());
        }
        return message;
    }
 
    protected ObjectMessage createMessageForSerializable(Serializable object, Session session) throws JMSException {
        return session.createObjectMessage(object);
    }
 
 
    protected String extractStringFromMessage(TextMessage message) throws JMSException {
        return message.getText();
    }
 
    protected byte[] extractByteArrayFromMessage(BytesMessage message) throws JMSException {
        byte[] bytes = new byte[(int) message.getBodyLength()];
        message.readBytes(bytes);
        return bytes;
    }
 
    protected Map extractMapFromMessage(MapMessage message) throws JMSException {
        Map<String, Object> map = new HashMap<String, Object>();
        Enumeration en = message.getMapNames();
        while (en.hasMoreElements()) {
            String key = (String) en.nextElement();
            map.put(key, message.getObject(key));
        }
        return map;
    }
 
    protected Serializable extractSerializableFromMessage(ObjectMessage message) throws JMSException {
        return message.getObject();
    }
 
}

... 에서http://haohaoxuexi.iteye.com/blog/1900937)

좋은 웹페이지 즐겨찾기