說明: 本文并非基礎說明文章,如無基礎,請先參閱:
1. http://wiki.springside.org.cn/display/springside/ActiveMQ
2. http://wiki.springside.org.cn/display/springside/ActiveMQ-part2
僅以springside-2.0-RC1版本擴展
由于為每個POJO類實現自己的MessageConverter ,所以配置xml和使用比較繁瑣。
一.MessageConverter 擴展
在springside-2.0-RC1版本中
<!-- Spring JmsTemplate config -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory">
<!-- lets wrap in a pool to avoid creating a connection per send -->
<bean class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory" ref="jmsConnectionFactory"/>
</bean>
</property>
<!-- custom MessageConverter -->
<property name="messageConverter" ref="orderMessageConverter"/>
</bean>
<!-- OrderMessage converter -->
<bean id="orderMessageConverter" class="org.springside.bookstore.components.activemq.OrderMessageConverter"/>

orderMessageConverter為 MessageConverter實現類。
但是如果在實際項目中應用的話,如果為2個或2個以上的pojo 實現MessageConverter的話,那么就會發現jmsTemplate讓人比較尷尬的位置,啟動的注入messageConverter也不是,動態messageConverter也不是, 顯的不是那么平易近人了。
自己的擴展
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory">
<!-- lets wrap in a pool to avoid creating a connection per send -->
<bean class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory" ref="jmsConnectionFactory"/>
</bean>
</property>
<property name="messageConverter" ref="messageConverter"/>
</bean>

<!-- Holder Message converter -->
<bean id="messageConverter" class="com.service.CoverterHolder" />

通過通用的CoverterHolder分發messageConverter實現,可以為多個pojo提供MessageConverter,并且有默認的messageConverter實現,并且可以通過 set Map<String, MessageConverter> converters 注入,提供特殊的pojo的MessageConverter的實現,為真正項目中應用提供必要的支持。
com.service.CoverterHolder 代碼為:

public class CoverterHolder implements MessageConverter
{
private MessageConverter defaultMessageConverter;
private Map<String, MessageConverter> converters = new HashMap<String, MessageConverter>();

public Message toMessage(Object obj, Session session) throws JMSException
{
String clz = obj.getClass().getName();

if(converters.containsKey(clz))
{
Message message = converters.get(clz).toMessage(obj, session);
message.setObjectProperty("meta-class", clz);
return message;

}else
{
Message message=defaultMessageConverter.toMessage(obj,session);
message.setObjectProperty("default-meta-class", clz);
return message;
}
}


public Object fromMessage(Message msg) throws JMSException
{

if(msg.getObjectProperty("meta-class") != null)
{
String clz= msg.getObjectProperty("meta-class").toString();

if(converters.containsKey(clz))
{
return converters.get(clz).fromMessage(msg);
}

}else if(msg.getObjectProperty("default-meta-class") != null)
{
return defaultMessageConverter.fromMessage(msg);

}else
{
throw new JMSException("Msg:[" + msg + "] is not Map");
}
return null;
}


public void setConverters(Map<String, MessageConverter> converters)
{
this.converters = converters;
}


public void setDefaultMessageConverter(MessageConverter defaultMessageConverter)
{
this.defaultMessageConverter = defaultMessageConverter;
}

}

二.為大部分MessageConverter實現自己的默認功能
DefaultMessageConverter 為默認的MessageConverter實現,擺脫重復繁瑣的MessageConverter AG and AG,懶人的福音。哈哈
如果沒有特殊的要求,DefaultMessageConverter足以滿足90%以上的要求 。
DefaultMessageConverter代碼:

public class DefaultMessageConverter implements MessageConverter
{

public Message toMessage(Object obj, Session session) throws JMSException
{
// check Type
ActiveMQObjectMessage objMsg = (ActiveMQObjectMessage) session
.createObjectMessage();
HashMap<String, byte[]> map = new HashMap<String, byte[]>();

try
{
// POJO must implements Seralizable
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
map.put("POJO", bos.toByteArray());
objMsg.setObjectProperty("Map", map);


} catch (IOException e)
{
e.printStackTrace();
}
return objMsg;
}


public Object fromMessage(Message msg) throws JMSException
{

if (msg instanceof ObjectMessage)
{
HashMap<String, byte[]> map= (HashMap<String, byte[]>) ((ObjectMessage) msg).getObjectProperty("Map");

try
{
//POJO must implements Seralizable
ByteArrayInputStream bis=new ByteArrayInputStream(map.get("POJO"));
ObjectInputStream ois=new ObjectInputStream(bis);
return ois.readObject();

} catch (IOException e)
{
e.printStackTrace();

} catch (ClassNotFoundException e)
{
e.printStackTrace();
}
return null;

} else
{
throw new JMSException("Msg:[" + msg + "] is not Map");
}
}


在Spring中配置
<!-- Holder Message converter -->
<bean id="messageConverter" class="com.service.CoverterHolder">
<property name="defaultMessageConverter">
<bean class="com.service.DefaultMessageConverter"/>
</property>
</bean>

為 messageConverter 入住默認的MessageConverter實現。
三.為特殊的MessageConverter實現提供自己的選擇
例如 ReportPerdayMessageConverter為特殊的 POJO Coverter。
ReportPerdayMessageConverter代碼:

public class ReportPerdayMessageConverter implements MessageConverter
{

public Message toMessage(Object obj, Session session) throws JMSException
{
//…
}

public Object fromMessage(Message msg) throws JMSException
{
//…
}
}
在com.domain.ReportPerday模型中注入特殊的自己消息轉換
<!-- Holder Message converter -->
<bean id="messageConverter" class="com.service.CoverterHolder">
<!-- 擴展自己實現 converter -->
<property name="converters">
<map>
<entry key="com.domain.ReportPerday">
<bean id="reportPerdayMessageConverter" class="com.service.ReportPerdayMessageConverter"/>
</entry>
</map>
</property>
<property name="defaultMessageConverter">
<bean class="com.service.DefaultMessageConverter"/>
</property>
</bean>
四.
Message Driven POJO (MDP) 擴展Adapter
解決對多個消費者 MDP的分發
ss中配置
<!-- Message Driven POJO (MDP) -->
<bean id="messageListener" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
<constructor-arg>
<bean class="org.springside.bookstore.components.activemq.OrderMessageConsumer">
<property name="mailService" ref="mailService"/>
</bean>
</constructor-arg>
<!-- may be other method -->
<property name="defaultListenerMethod" value="sendEmail"/>
<!-- custom MessageConverter define -->
<property name="messageConverter" ref="orderMessageConverter"/>
</bean>
明顯感覺<constructor-arg>中對于多個消費者不實用的特性。
自己擴展
<!-- Message Driven POJO (MDP) -->
<bean id="messageListener" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
<!-- may be other method -->
<constructor-arg>
<bean class="com.service.MessageConsumerAdapter" >
<property name="reportPerdayMessageConsumer" ref="reportPerdayMessageConsumer"/>
</bean>
</constructor-arg>
<!-- may be other method -->
<property name="defaultListenerMethod" value="receive"/>
<!-- custom MessageConverter define -->
<property name="messageConverter" ref="messageConverter"/>
</bean>
MessageConsumerAdapter代碼:

public class MessageConsumerAdapter
{
private ReportPerdayMessageConsumer reportPerdayMessageConsumer;

public void receive(Object obj)
{

if (obj instanceof ReportPerday)
{
System.out.println((ReportPerday)obj);

} else if (obj instanceof ReportPerday2)
{
System.out.println((ReportPerday2)obj);
}
}


public void receive(ReportPerday reportPerday) throws Exception
{
reportPerdayMessageConsumer.sendEmail(reportPerday);
}

public void receive(ReportPerday2 reportPerday2) throws Exception
{
//do other service consumer
System.out.println("ReportPerday2 Bean do other service consumer ");
}

public void setReportPerdayMessageConsumer(

ReportPerdayMessageConsumer reportPerdayMessageConsumer)
{
this.reportPerdayMessageConsumer = reportPerdayMessageConsumer;
}
}
MessageConsumerAdapter中可以入住多個要分發的消費者或者業務方法,根據POJO對象不通而選擇自己的消費者類型。
后話: http://wiki.springside.org.cn 對ActiveMQ 實用已經比較細致的入門講解和展示。再次重申,如果沒基礎,請閱讀ss中的文檔。
本文目的只在搭建更為實用的JMS基礎設施,如有不明之處,共同討論與學習 :)
文中代碼如下
http://www.tkk7.com/Files/hellboys/activemq-example-nojar.zip