아래의 예제들은 JNDI를 사용하다는 전제로 소스를 만들었다.
ActiveMQ는 별도의 설정없이 바로 테스트 가능하지만, SonicMQ의 경우는
Sonic Magement Console의 JMS Administrator Objects 을이용하여 Connection Factories에 Lookup관련
사항을 등록하여야하고, Desincation에도 예제에서 사용한 T1을 등록해주어야한다.

Spring JmsTemplate을 사용함에 따라 각 벤더에서 사용하는 API를 정리할 수는 있지만,
각 벤더만의 API 가지는 장점을 사용하기 위해서는 좀 더 세련된 소스 형태로 고민을 해야될 것이다.
(아래의 예제는 가장 간단히 주고, 받기만을 할 수 있는 예제이며 설정이다.)

그리고, (1)에서도 잠시 언급한 JmsTemplate Gotchas 를 꼭 읽어보고, 이에 대한 부분도 함께 고려하여야
할 것이며, James Strachan 이 설계한 lingoJencks 도 살펴보길 바란다.

다음엔 이를 좀 더 확장하여, ServiceMix와 Celtix, mule 에 통합하는 것을 다뤄볼까 한다.

아래의 내용은 소스는 다음에서 받을 수 있다.
클릭
Posted by 아름프로

소스는 ActiveMQ의 소스와 같으며, 해당 xml은 아래와 같다.

sonicmq_receive.xml

<?xml version="1.0" encoding="euc-kr"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

<bean id="start" class="java.lang.String"/>

<bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref bean="jndiTemplate"/>
</property>
<property name="jndiName">
<value>OUTTER_CB_URL</value>
</property>
</bean>

<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">
com.sonicsw.jndi.mfcontext.MFContextFactory
</prop>
<prop key="java.naming.provider.url">
tcp://222.112.180.61:2506
</prop>
<prop key="com.sonicsw.jndi.mfcontext.domain">
Domain1
</prop>
<prop key="java.naming.security.principal">
Administrator
</prop>
<prop key="java.naming.security.credentials">
Administrator
</prop>
</props>
</property>
</bean>

<bean id="destination" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref bean="jndiTemplate" />
</property>
<property name="jndiName">
<value>T1</value>
</property>
</bean>

<bean id="messageListener" class="org.jtop.spirng.sample.sonicmq.receive.Receiver" />

<bean id="listenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="destination" />
<property name="messageListener" ref="messageListener" />
</bean>
</beans>


Posted by 아름프로
소스 부분은 AciveMQ에서의 예제와 같으며, 실행 소스상에서의 아래 xml로 적용.

sonicmq_send.xml 부분
<?xml version="1.0" encoding="euc-kr"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

<bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref bean="jndiTemplate"/>
</property>
<property name="jndiName">
<value>OUTTER_CB_URL</value>
</property>
</bean>

<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">
com.sonicsw.jndi.mfcontext.MFContextFactory
</prop>
<prop key="java.naming.provider.url">
tcp://222.112.180.61:2506
</prop>
<prop key="com.sonicsw.jndi.mfcontext.domain">
Domain1
</prop>
<prop key="java.naming.security.principal">
Administrator
</prop>
<prop key="java.naming.security.credentials">
Administrator
</prop>
</props>
</property>
</bean>

<bean id="destination" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref bean="jndiTemplate" />
</property>
<property name="jndiName">
<value>T1</value>
</property>
</bean>

<bean id="rankSender" class="org.jtop.spirng.sample.sonicmq.send.Sender">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="destination" />
</bean>
</beans>


Posted by 아름프로
메시지 받기 (onMessage)

package org.jtop.spirng.sample.activemq.receive;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
*
* @author lee
*/
public class Receiver implements MessageListener {

Log log = LogFactory.getLog(this.getClass());

public void onMessage(Message message) {
try {
TextMessage tm = (TextMessage)message;
log.debug("Property : " + tm.getStringProperty("Property"));
log.debug("Text : " + tm.getText());
} catch (JMSException e) {
log.error("onMessage Exception : ", e);
}
}
}


실행하는 클래스

package org.jtop.spirng.sample.activemq.receive;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class Runner{

Log log = LogFactory.getLog(this.getClass());

private void run() {
ApplicationContext ctx = new FileSystemXmlApplicationContext("conf/activemq/activemq_receive.xml");
ctx.getBean("start");
log.info("============= onMeesage() ==============");
}

public static void main(String[] args) {
Runner job = new Runner();
job.run();
}
}



activemq_receive.xml 내용

<?xml version="1.0" encoding="euc-kr"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

<!-- === XML이 로딩되면서 자동으로 messageListener 동작(start는 단순 로딩용) === -->
<bean id="start" class="java.lang.String"/>

<bean id="r_connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref bean="r_jndiTemplate"/>
</property>
<property name="jndiName">
<value>ConnectionFactory</value>
</property>
</bean>

<bean id="r_jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">
org.apache.activemq.jndi.ActiveMQInitialContextFactory
</prop>
<prop key="java.naming.provider.url">
tcp://localhost:61616
</prop>
</props>
</property>
</bean>

<bean id="r_destination" class="org.apache.activemq.command.ActiveMQTopic" autowire="constructor">
<constructor-arg value="FOO.BAR" />
</bean>

<bean id="messageListener" class="org.jtop.spirng.sample.activemq.receive.Receiver" />

<bean id="listenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="r_connectionFactory" />
<property name="destination" ref="r_destination" />
<property name="messageListener" ref="messageListener" />
</bean>

</beans>
Posted by 아름프로
두 MQ모두 Sample(or Example)에 보면 Connection 생성에서부터 각자의 Connection 클래스로 생성하게
되어 있어, 한쪽에서 개발을 한 다음에는 다른 MQ로의 사용이 어렵게 되어 있다.
이에 Spring의 JmsTemplate을 사용하여, 좀 더 쉬운 방법으로의 통합된 형태의 간단한 예제를 작성해본다.
(단, JmsTemplate Gotchas 을 읽어보고, JmsTemplate을 적용에 주의를 요한다.)

메시지 Send

package org.jtop.spirng.sample.activemq.send;

import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;

public class Sender {

Log log = LogFactory.getLog(this.getClass());

private JmsTemplate jmsTemplate;
private Destination destination;

public void setConnectionFactory(ConnectionFactory cf){
jmsTemplate = new JmsTemplate(cf);
}

public void setDestination(Destination des){
this.destination = des;
}

public void send(){
this.jmsTemplate.send(this.destination, new MessageCreator(){
public Message createMessage(Session session) throws JMSException {
Message ms = session.createTextMessage("Example Message");
ms.setStringProperty("Property", "Example");
return ms;
}
});
}
}

실행하는 클래스

package org.jtop.spirng.sample.activemq.send;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class Runner{

Log log = LogFactory.getLog(this.getClass());

private void run() {
ApplicationContext ctx = new FileSystemXmlApplicationContext("conf/activemq/activemq_send.xml");
Sender sender = (Sender)ctx.getBean("sender");
sender.send();
log.info("============= Send ==============");
}

public static void main(String[] args) {
Runner job = new Runner();
job.run();
}
}

activemq_send.xml 내용

<?xml version="1.0" encoding="euc-kr"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
<!-- ======================== Sender =========================== -->
<bean id="s_connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref bean="s_jndiTemplate"/>
</property>
<property name="jndiName">
<value>ConnectionFactory</value>
</property>
</bean>

<bean id="s_jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">
org.apache.activemq.jndi.ActiveMQInitialContextFactory
</prop>
<prop key="java.naming.provider.url">
tcp://localhost:61616
</prop>
</props>
</property>
</bean>

<bean id="s_destination" class="org.apache.activemq.command.ActiveMQTopic" autowire="constructor">
<constructor-arg value="FOO.BAR" />
</bean>

<bean id="sender" class="org.jtop.spirng.sample.activemq.send.Sender">
<property name="connectionFactory" ref="s_connectionFactory" />
<property name="destination" ref="s_destination" />
</bean>
</beans>



Posted by 아름프로

Lingo 와 Jencks

2006. 5. 12. 11:45
codehaus.org 프로젝트에 보면, ActiveMQ와 연계되는 프로젝트에 Lingojencks 라는 것이 있다.
1년전 MQ들의 통합과 이들을 다시 ESB기반의 Open 제품과 사용제품과 함께 통합할 수 있는
것을 만들어보고자, Spring 기반에서 고민한 적이 있는데, 현 시점에는 이들이 그것을 가능케해주는데 있어서
중요한 기능을 담당할 수 있을 듯하다.
Geronimo에 포함되어져 있어 앞으로도 계속 업그레드되어지리라 보여진다.

두 프로젝트 모두, 개인적으로 좋아라하는 james strachan 이 프로젝트 리더로 이끌고 있다.

Lingo :
[CODE] JMS기반위에 Spring Remoting을 구현한 녀석으로, JMS를 사용면서 POJOs의 뒤로 JMS의 사용을 숨길 수가 있다. (다시 말해서, 원격지의 데이터 전송에 있어 Spring을 사용(Spring Remoting)하여, JMS의 사용에 대한 부분은 캡슐화 시켜준다.) [/CODE]
Jencks :
[CODE] Spirng을 내에 JMS와 JDBC pooling을 이용하여 Message Driven POJOs를 구현한 녀석으로 (lightweight JCA 컨테이너와 Resource Adapters를 사용한다.), EJB를 사용하지 않으며, MDB와 같은 역할을 한다. [/CODE]
Posted by 아름프로
아래의 내용처럼 기본적으로는 weblogic8.1에서는 JMS1.1 기반으로 사용이
불가능합니다.

1.1을 지원하고 있지는 않는 상황이고, 또한 공식적으로 1.1에 대한 지원에 대한
부분도 언급을 하고 있지는 않습니다.
문서상에 1.1을 받으라고는 나오지만 어떻게 해서 사용하라고하는 내용도 제공하지 않습니다.

포럼을 뒤져서 그나마 환경설정을 변경해서 편법적으로 사용한다는 글이 하나
있어서 테스트 해보니, 기본적인 기능에서는 처리가 되었기에 적어봅니다.

======================================

user_project의 프로젝트와 도메인의 start는 쫓아가보니 실행을 위한 환경설정 부분이 "C:\bea\weblogic81\common\bin" 의 commEnv.cmd 를 실행하면서 설정을 하게 되어있습니다.

이 파일을 열어보면
WEBLOGIC_CLASSPATH 라는 부분이 있습니다.
여기에 보면, weblogic.jar 파일이 등록되어져 있는 것을 보실 수 있습니다.
weblogic은 이 파일에 j2ee의 관련 api들을 한꺼번에 묶어서 제공을 합니다.
그렇기 때문에

이 파일의 앞쪽에 "http://java.sun.com/products/jms/docs.html"
여기에서 jms1.1 을 라이브러리 파일을 받은 후에 자신의 PC에 두고,
패스를 잡아주시면 됩니다.

예)
set WEBLOGIC_CLASSPATH=C:\Java\lib\jms.jar;%JAVA_HOME%\lib\tools.jar;%WL_HOME%\server\lib\weblogic_sp.jar;%WL_HOME%\server\lib\weblogic.jar

======================================
Posted by 아름프로
JMS Specification
WebLogic Server is fully compliant with version 1.0.2b of the JMS Specification, and can be used in production.

Note: As of the release date for WebLogic Server 8.1, Sun Microsystems has not certified any JMS implementation as being compliant with the version 1.1 JMS Specification. To use the WebLogic JMS implementation of the version 1.1 JMS Specification, use the link provided above to download the version 1.1 API documentation, JAR, and source files.

Posted by 아름프로

JMS 1.0.2b -> 1.1

2005. 7. 8. 23:56

JavaTM Message Service 1.1


February 11, 2002

Updated March 04, 2002




Description


Maintenance
version of the JavaTM Message Service specification, version 1.1.


Specification Lead


Kate Stout,
Sun Microsystems, Inc.


Feedback


Comments should
be sent to jets-jms@sun.com


 

Rationale for proposed changes

This maintenance
release addresses the unification of the programming interfaces for the Point-to-Point
and Pub/Sub messaging domains in the Java Message Service (JMS) API. In the
existing version of the specification, the client programming model make
a strong distinction between these two domains. One consequence of domain 
separation is that actions from the Point-to-Point domain and the Pub/Sub
domain in can not be used in the same transaction.


In this proposed
domain unification of the interfaces, methods have been added to support
the ability to include PTP and Pub/Sub messaging in the same transaction.
In addition, the domain unification proposed simplifies the client programming
model, so that the client programmer can use a simplified set of APIs to create
an application.


This proposal
is





  • Fully backwards compatible;
    existing implementations will work as is.





  • Semantically compatible;
    semantic differences between the two messaging domains are retained






The scope
of a transaction in JMS is on a per Session basis. To add the ability to
work across both domains, a number of methods have been added the the javax.jms.Session
interface. Adding these methods supports the creation of javax.jms.MessageConsumers
and javax.jms.MessageProducers for either domain at the Session level, and
support  sending and receiving message from either domain within the
same Session. For example, using these proposed methods, an application can
create a transacted Session, and then receive messages from a Queue and send
messages to a Topic within the same transaction. In JMS 1.0.2b, this is not
possible.


See
Domain Unification

for details of the changes. See Examples
to get more details on how these changes could be used.



 

In addition to the interface changes for
domain unification, there are several minor specification clarifications and
enhancements are proposed. These have been detailed below in
Other Changes

.








Proposed Changes



Domain unification



The following are the changes proposed to support the unification of the
domain-specific interfaces. It is arranged by alphabetically by interface.



 

Connection


Add
methods to support domain unification:



ConnectionConsumer
createConnectionConsumer(Destination destination, String messageSelector,
ServerSessionPool sessionPool, int maxMessages) throws JMSException;



ConnectionConsumer createDurableConnectionConsumer(Topic topic,String
subscriptionName, String messageSelector, ServerSessionPool sessionPool,
int maxMessages) throws JMSException;



Session createSession(boolean transacted, int acknowledgeMode) throws
JMSException;




ConnectionFactory


Add
methods to support domain unification:




Connection createConnection() throws JMSException;



Connection createConnection(String userName, String password) throws
JMSException;




MessageProducer



Add methods to support domain unification:




Destination getDestination() throws JMSException;



void send(Message message) throws JMSException;



void send(Message message, int deliveryMode, int priority, long timeToLive)
throws JMSException;



void send(Destination destination, Message message) throws JMSException;



void send(Destination destination, Message message, int deliveryMode,
int priority, long timeToLive) throws JMSException;




Session



Add methods to support domain unification:




MessageProducer createProducer(Destination destination) throws JMSException;



MessageConsumer createConsumer(Destination destination) throws JMSException;



MessageConsumer createConsumer(Destination destination, java.lang.String
messageSelector) throws JMSException;



MessageConsumer createConsumer(Destination destination, java.lang.String
messageSelector, boolean NoLocal) throws JMSException;



TopicSubscriber createDurableSubscriber(Topic topic, java.lang.String
name) throws JMSException;



TopicSubscriber createDurableSubscriber(Topic topic, java.lang.String
name, java.lang.String messageSelector, boolean noLocal) throws JMSException;



QueueBrowser createBrowser(Queue queue) throws JMSException;



QueueBrowser createBrowser(Queue queue, String messageSelector) throws
JMSException;



Queue createQueue(String name) throws JMSException;



Topic createTopic(String name) throws JMSException;



TemporaryTopic createTemporaryTopic() throws JMSException;



TemporaryQueue createTemporaryQueue() throws JMSException;



void unsubscribe(String string name)




XAConnection



Add method to support domain unification




XASession createXASession() throws JMSException;




XAConnectionFactory



Add methods to support domain unification:




XAConnection createXAConnection() throws JMSException;



XAConnection createXAConnection(String userName, String password)
throws JMSException;




Other Changes


 



BytesMessage



Enhancement
: Add method




int getBodyLength() throws JMSException




Added to support the ability to get a body length which can be used to allocate
a bytes array.


 



Connection



Clarification
: If Connection.getExceptionListener is called, and no ExceptionListener
is registered, the JMS provider must return null.


 

MapMessage



Clarification
: For each set method, if the name parameter is null or
empty string, throw NullPointerException



Methods affected: setByte, setBytes, setChar, setDouble,
setFloat,setInt, setLong,setObject, setShort,setString



 

Message



Clarification
: For each set property method, if the property name parameter
is null or empty string, throw NullPointerException.



Methods affected: setBooleanProperty, setByteProperty, setDoubleProperty,
setFloatProperty, setIntProperty, setLongProperty, setObjectProperty, setShortProperty,
setStringProperty



 

TextMessage



Clarification
: Changed a comment that indicated that XML might become
popular to a statement that TextMessage can be used to send XML messages.


 

Session



Enhancement
: Add Method




int getAcknowledgeMode() throws JMSException




This method gets value for how messages are acknowledged. Previously there was no method to get the AcknowledgeMode value.



 



XA



Clarification:
Added a comment that the XA interfaces are primarily used
by JMS providers, and are optional.



Interfaces effected: XAConnection, XAConnectionFactory, XAQueueConnection,
XAQueueConnectionFactory, XAQueueSession, XASession, XATopicConnection, XATopicConnectionFactory,
XATopicSession


 


Examples of domain unification
of the interfaces



In this section, some code examples of common JMS client tasks are given
to show the current approach and the proposed approach.



Example 1: Setting up a connection and session




JMS 1.0.2b




JMS 1.1



 

Example
2: Creating a Message Producer to a topic




JMS 1.0.2b




JMS 1.1



 


Example
3 - Adding a Message Producer to a queue




JMS 1.0.2b




JMS 1.1





Example 1: Setting
up a connection and session.



JMS 1.0.2b



Use TopicConnectionFactory, TopicConnection and TopicSession to setup.



Context jndiContext = null;



TopicConnectionFactory topicConnectionFactory = null;



TopicConnection topicConnection = null;



TopicSession topicSession = null;



Topic topic = null;



//Create a JNDI InitialContext object if none exists yet.



jndiContext = new InitialContext();



// Look up connection factory and topic.



topicConnectionFactory = (TopicConnectionFactory)



               
jndiContext.lookup("TopicConnectionFactory");



topic = (Topic) jndiContext.lookup("StockQuoteTopic");



//Establish TopicConnection and TopicSession



topicConnection = topicConnectionFactory.createConnection();



topicSession = topicConnection.createTopicSession(false,



               
Session.AUTO_ACKNOWLEDGE);



 


JMS 1.1



Use ConnectionFactory, Connection and Session to setup.



Context jndiContext = null;



ConnectionFactory connectionFactory = null;



Connection connection = null;



Session session = null;



Topic topic = null;



// Create a JNDI InitialContext object if none exists yet.



jndiContext = new InitialContext();



// Look up connection factory and topic.



connectionFactory = (ConnectionFactory)



jndiContext.lookup("TopicConnectionFactory");



topic = (Topic) jndiContext.lookup("StockQuoteTopic");



//Establish Connection and Session



connection = connectionFactory.createConnection();



session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);



 


Example
2: Creating a message producer (to a topic)



Set a message producer that can send messages



JMS 1.0.2.b



Sets up a TopicPublisher and sends messages on a TopicSession



 



// Create a TopicPublisher and send a message



TopicPublisher topicPublisher = null;



topicPublisher = topicSession.createPublisher(topic);



message = topicSession.createTextMessage("A message body");



topicPublisher.publish(message);



JMS 1.1



Sets up a MessageProducer and sends messages on a Session.



// Create a Message Producer and send a message



MessageProducer messageProducer = null;



messageProducer = session.createProducer((Destination)topic);



message = session.createTextMessage("A message body");



messageProducer.send(message);



 


Example
3: Adding a Message Producer to a queue



The client programming simplification can be seen if we now try to add a
Message producer that will send messages to a Queue.


 



JMS 1.0.2b



To do this, the application must:





    Lookup QueueConnectionFactory



    Lookup Queue



    Create QueueConnection



    Create QueueSession



    Create QueueSender



    Create Message



    send message using QueueSender.send();





QueueConnectionFactory queueConnectionFactory = null;



QueueConnection queueConnection = null;



QueueSession queueSession = null;



Queue queue = null;



// Look up connection factory and queue.



queueConnectionFactory = (QueueConnectionFactory)



jndiContext.lookup("QueueConnectionFactory");



queue = (Queue) jndiContext.lookup("WorkFlowQueue");



//Establish QueueConnection and QueueSession



queueConnection = queueConnectionFactory.createQueueConnection();



queueSession = queueConnection.createQueueSession(false,Session.AUTO_ACKNOWLEDGE);



// Setup queue sender



QueueSender queueSender = null;



queueSender = queueSession.createSender(queue);



message = queueSession.createTextMessage("A message body");



queueSender.send(message);



 


JMS 1.1



By contrast, the unified model can re-use the Connection and Session that
has already been established. The additional steps are:





    Lookup Queue



    Create MessageProducer



    Create Message



    Send message using MessageProducer.send()





// Lookup Queue



queue = (Queue) jndiContext.lookup("WorkFlowQueue");



// setup Message producer



MessageProducer workFlowProducer = null;



workFlowProducer = session.createProducer((Destination)queue);



message = session.createTextMessage("A message body");



workFlowProducer.send(message);



 

 
Posted by 아름프로

JMS 정리 잘 된 내용 ...

2003. 1. 21. 13:47
요약
J2EE의 한 부분인 자바 메시지 서비스(Java Message Service; JMS)는 안정하고, 확장 가능한 분산 어플리케이션을 제작할 수 있도록 해 준다. 또한 메시징 시스템은 서로 다른 네트워크 사이를 쉽게 통합할 수 있도록 해 주며, 높은 확장성을 제공해준다. 이 글에서는 메시징 시스템의 전체적인 개념과 JMS를 이용하여 메시징 시스템을 어떻게 구현하는지에 대해서 간단하게 알아보도록 한다.


프로바이더: 최범균, madvirus@tpage.com
----------------------------------------------------------------------

분산 어플리케이션이 급격히 증가하면서 따라서 이전에 발생하지 않았던 동기화, 안정성, 확장성 그리고 보안 등에서 문제가 발생하기 시작하였다. 이에 대한 한가지 해결책은 메시지를 통해 각 컴포넌트 사이의 결합성(coupling)을 약화시키는 메시징 시스템이다.

메시징 시스템은 안정하고, 확장 가능하고 그리고 유연한 분산 어플리케이션을 제작하기 위해 사용된다. 이 글에서는 일반적인 메시징 시스템에 대한 내용과 메시징 시스템의 종류에 대해서 알아보며, 그런 후 개발자들이 JMS(Java Message Service; 자바 메시지 서비스)를 이용하여 메시지 기반의 어플리케이션을 어떻게 작성할 수 있는지에 대해서 알아본다.

메시징 시스템
메시징 시스템은 분리된 결합되어 있지 않은 어플리케이션이 비동기적으로 신뢰성있게 통신할 수 있도록 해 준다. 메시징 시스템 아키텍처는 일반적으로 각 컴포넌트 사이의 관계를 클라이언트/서버 모델에서 피어-투-피어(peer-to-peer) 관계로 변경한다. 각각의 피어는 다른 피어에 메시지를 전송할 수 있으며, 또한 다른 피어로부터 메시지를 전달받을 수 있다.

메시징 시스템은 고전적인 분산 컴퓨팅 모델에 비해 더욱 강력한 장점을 제공한다. 먼저, 메시징 시스템은 메시지 소비자(message consumers)와 메시지 생산자(message producer)가 약한 결합성(loose coupling)을 갖도록 한다. 메시지 생산자와 소비자는 서로를 거의 알지 못한다. 메시지 소비자에게 있어서, 그 메시지를 누가 생산했고 생선자가 어디에 있는 지 또는 메시지가 언제 생산되었는지의 여부는 문제가 되지 않는다.

이러한 메시징 시스템의 특징은 동적이고, 신뢰성 있고 유연한 시스템을 구현할 수 있도록 해 주며, 그에 따라 시스템의 나머지 부분에 영향을 않고 하위 어플리케이션의 전체적인 구성을 변경할 수 있다.

메시징 시스템의 또 다른 장점은 높은 확장성, 서로 다른 네트워크 사이의 쉬운 통합 그리고 안정성이다.

메시징 시스템의 안정적이고 확장가능한 특징 때문에, 많은 비지니스와 컴퓨팅 사이언스 문제를 해결하기 위해 메시징 시스템을 사용하고 있다. 예를 들어, 메시징 시스템은 워크플로우, 네트워크 관리, 통신 서비스, 고객 관리, 일기 예보 시스템과 같은 다양한 어플리케이션의 기반이 되고 있다. 또한, 메시징 시스템은 통합이 필연적인 분리된 시스템들을 엮어주는 매개체로서의 중요한 역할을 하고 있다.

메시징 시스템의 종류
일반적으로 사용되는 메시징 시스템의 종류에는 출판/구독(Publish/Subscribe) 방식과 포인트-투-포인트(Point-To-Point) 방식의 두 종류가 있다.

출판/구독(Publish/Subscribe) 방식
출판/구독 메시징 시스템은 메시지의 전송에 참여하고 있는 생산자(producer)와 소비자(consumer)가 이벤트를 사용하여 통신한다. 생산자는 이벤트를 "출판(즉, 발생)"하고 소비자는 자신이 관심을 갖고 있는 이벤트를 "구독"하여 그 이벤트를 소비한다. 생산자는 메시지를 특정한 토픽과 연관시키며, 그 메시지는 그 메시지와 관련된 토픽에 등록한 소비자에게 전달된다.

점대점(Point-To-Point) 방식
점대점(Point-To-Point) 메시징 시스템에서 메시지는 개개의 소비자에게 전달되며, 각각의 소비자는 들어오는 메시지를 저장하는 큐를 갖고 있다. 메시징 어플리케이션은 지정된 큐에 메시지를 보내고, 클라이언트는 큐로부터 메시지를 읽어들인다.

Java Message Service
자바 메시지 서비스는 J2EE(Java 2 Enterprise Edition)의 부분이며, 자바 개발자들이 엔터프라이즈 메시지 시스템의 공통적인 특징에 접근하기 위해 사용할 수 있는 표준 API를 제공한다. JMS는 출판/구독 모델과 포인트-투-포인트 모델을 지원하며, 임의의 자바 객체로 구성된 메시지 타입을 생성할 수 있도록 해 준다.

디자인 목적
JMS의 기본적인 설계 목적은 메시징 시스템의 클라이언트가 하부의 메시징 시스템 프로바이더에 독립적으로 사용할 수 있는 일관된 인터페이스 집합을 제공하는 것이다.

JMS는 머신 아키텍처와 운영체제에 상관없이 클라이언트 어플리케이션이 이식성을 갖도록 해줄 뿐만 아니라, 또한 메시징 제품에 상관없는 이식성을 갖도록 해 준다. JMS로 작성된 클라이언트 애플리케이션은 JMS 호환 메시징 시스템에서 변경할 필요 없이 사용할 수 있다.

JMS는 또한 다음과 같은 목적으로 설계되었다.

메시징 시스템 프로바이더가 그들의 제품을 위해 JMS API를 구현하기 위해 필요한 노력을 최소화시켜준다.
대부분의 일반적인 메시징 시스템 기능을 제공한다.
많은 메시징 시스템 벤더들은 그들의 제품에 맞게 JMS를 구현하였으며, 따라서 자바를 사용하여 시스템의 기능에 접근할 수 있도록 하고 있다.

JMS 클라이언트는 자바의 특징을 사용한다
JMS 클라이언트는 자바를 기반으로 하고 있기 때문에 JDBC, 자바빈 컴포넌트, JNDI, JTA 또는 JavaMail 등의 기존의 존재하는 자바 API를 사용할 수 있다.

JMS의 세부 내용
이제부터 JMS를 사용한 메시징 시스템의 클라이언트를 작성하는 것에 대해서 좀 더 세부적으로 알아보도록 하자. 먼저 알아볼 내용은 메시징 시스템의 가장 기본 요소인 메시지이다.

메시지
메시징 시스템에서 어플리케이션 간의 통신의 핵심은 메시지이며, 따라서 JMS를 사용하는 개발자들은 메시지에 대해 이해하고 있어야 한다. 메시징 시스템에 따라 메시지의 정의가 다양하기 하지만, JMS는 메시지를 설명하고 접근하는 통합된 의미를 사용하고 있다. JMS에서 메시지는 세 부분으로 구성되어 있다.

메시지 헤더 메시지를 구분하기 위해 사용된다. 예를 들어, 주어진 메시지가 특정 구독자에게 알맞은 것인지를 판단하기 위해 헤더를 사용한다. 프로퍼티 어플리케이션에 특정한 값, 프로바이더에 특정한 값 그리고 추가적인 헤더 필드를 제공하기 위해 사용된다. 몸체 메시지의 내용을 저장한다. TestMessage나 ObjectMessage와 같은 다양한 포맷을 지원한다. TextMessage
TextMessage는 Strign 객체를 감싸고 있다. 이 객체는 단지 문자열만 전송할 때 유용하게 사용할 수 있다. 앞으로 많은 메시징 시스템들이 XML 기반으로 될 것으로 예상되기 때문에, TextMessage는 대부분의 메시징 시스템에서 지원될 것이다.

TextMessage 객체를 생성하는 것은 매우 간단하며, 다음과 같은 두줄만으로 생성할 수 있다.


TextMessage message = session.createMessage();
message.setText("hello world!");


이런 방법으로 생성된 TextMessage 객체는 메시징 시스템에 출판할 준비가 된 것이다.

ObjectMessage
ObjectMessage 객체는 그 이름에서 알 수 있듯이 일반적인 자바 객체를 감싸고 있는 메시지이다. 모든 직렬화가능한 자바 객체를 ObjectMessage로 사용할 수 있다. 만약 하나의 메시지에 다중의 객체를 전송해야 한다면, List나 Set과 같은 콜렉션(Collection)객체를 사용하면 된다. 이 경우, 콜렉션 객체는 직렬화가능한 객체만을 저장하고 있어야 한다.

ObjectMessage 객체는 다음과 같이 생성한다.


ObjectMessage message = session.createObjectMessage();
message.setObject(somObject);


JNDI와 관련해서 알아야 할 점
J2EE의 다른 API와 마찬가지로 JMS는 필요한 자원을 찾기 위해서 JNDI(Java Naming and Directory Interface)를 사용한다. JNDI에 대한 내용은 이 글의 범위를 넘어서므로, JNDI에 대해서 자세히 알고 싶다면 JNDI 홈페이지를 참조하기 바란다.

JMS 클라이언트 작성
일반적은 JMS 클라이언트는 다음의 기본적인 3 단계를 통해서 작성된다.

메시징 시스템 프로바이더와 연결된 커넥션을 생성한다.
메시지를 전송하기 받기 위한 세션을 생성한다.
메시지를 생성하고 받기 위해 MessageProducer와 MessageConsumer를 생성한다.
이 과정을 수행하면, 메시지를 생성하는 클라이언트는 메시지를 생성한 후 특정 주제로 그 메시지를 출판할 수 있다. 반면에 메시지를 소비하는 클라이언트는 자신이 관심을 갖는 주제와 관련된 메시지를 기다리고 있다가 메시지가 도착하면 그것을 소비한다.

실제로 어떻게 이런 것들이 이루어지는 알아보기 위해 출판/구독 메시징 시스템에서 특정 주제와 관련된 메시지를 출판하는 메시지 생산자에 대해 살펴보기로 하자. 좀더 쉽게 알아볼 수 있도록 하기 위해 예외 처리와 관련된 코드는 생략하였다.

메시징 시스템 프로바이더에 연결하기
커넥션(Connection)은 클라이언트가 하부의 메시징 시스템에 접근할 수 있도록 해 주며, 자원 할당과 관리를 수행한다. ConnectionFactory를 사용하여 커넥션을 생성한다. ConnectionFactory는 일반적으로 JNDI를 사용하여 위치시킨다.

다음 코드는 커넥션 생성 단계와 관련된 부분을 보여주고 있다.


Context messaging = new InitialContext();
// JNDI 콘텍스트를 구한다.
TopicConnectionFactory topicConnectionFactory =
(TopicConnectionFactory)messaging.lookup("TopicConnectionFactory");
TopicConnection topicConnection =
topicConnectionFactory.createTopicConnection();


세션 생성
세션은 메시지 생산과 소비를 위한 콘텍스트를 제공하는 경량의 JMS 객체이다. 메시지 생산자와 소비자를 생성할 때 세션을 사용하여 또한 메시지를 생성할 때에도 세션을 사용한다.


TopicSession session =
topicConnection.createTopicSession(false, Session.CLIENT_ACKNOWLEDGE);


createTopicSession() 메소드에 전달되는 두 파라미터는 각각 트랜잭션과 메시지 인식을 제어한다.

토픽 지정
토픽(주제, 그룹 또는 채널이라고도 한다)은 JNDI를 통해서 위치시킬 수 있다. 토픽은 전송되거나 수신된 메시지를 분류한다. 출판/구독 시스템에서, 구독자는 주어진 토픽을 구독하며, 출판자는 그들이 출판한 메시지를 특정한 토픽과 연관시킨다.

다음은 "StockData"라고 불리는 토픽을 생성하는 코드를 보여주고 있다.


Topic stockTopic = messaging.lookup("StockData");


커넥션 시작
위의 과정을 거치는 동안에 메시지의 흐름은 초기화하는 동안에 예측할 수 없는 행동을 하지 못하도록 하기 위해 억제된다. 일단 초기화가 끝나면, 커넥션은 반드시 메시지 이름을 시작해야 한다.


topicConnection.start();


메시지 생산자 생성
출판/구독 시스템에서, 생산자는 주어진 토픽에 메시지를 출판한다. 다음 코드는 출판자를 생성하고 이어서 간단한 텍스트 메시지를 출판하는 것을 보여주고 있다.


TopicPublisher publisher =
session.createPublisher(stockTopic);
TextMessage message = session.createMessage();
message.setText("kosdaq: 101");

publisher.publish(message);


비슷한 과정을 통해서 구독자를 생성할 수 있으며, 또한 점대점 시스템을 위한 JMS 클라이언트를 생성할 수 있다.

결론
이 글에서는 메시징 기반의 어플리케이션을 작성하기 위해 JMS를 사용하는 것과 관련된 기본적인 개념에 대해서 살펴보았다. JMS 호환 시스템의 목록은 "JMS 호환 벤더 목록"을 참고하기 바란다.

----------------------------------------------------------------------
javacan.com 출처



***** 아름다운프로님에 의해서 게시물 복사 + 카테고리변경되었습니다 (2003-12-18 17:45)
Posted by 아름프로

BLOG main image

카테고리

분류 전체보기 (539)
이야기방 (19)
토론/정보/사설 (16)
IBM Rational (9)
U-IT (0)
SOA/WS/ebXML (110)
개발방법론/모델링 (122)
J2SE (34)
J2EE (60)
JDO (7)
JSP (2)
Java XML (5)
Java Mail (0)
JSF (1)
JMS (10)
Servlet (0)
Security (0)
Transactions (0)
Connector Arch (0)
WAS (8)
개발툴 (4)
JSTL (0)
Interoperability (1)
docs (6)
RMI (1)
JBI (2)
Rules Engine (1)
EJB (5)
JDBC (7)
DataBase (39)
Open Projects (30)
BP/표준화 (50)
Apache Projects (15)
Web/보안/OS (22)
Tools (7)
AJAX/WEB2.0 (1)
Linux/Unix (1)
영어 (0)
비공개방 (0)

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

달력

«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28

글 보관함

Total :
Today : Yesterday :