24.6 JMS

使用JMS来作为底层的通信协议透明暴露服务也是可能的。Spring框架中对JMS的远程支持也很基础 – 它在同一线程和同一个非事务 Session上发送和接收,这些吞吐量将非常依赖于实现。需要注意的是这些单线程和非事务的约束仅适用于Spring的JMS远程处理支持。请参见 第26章, JMS (Java消息服务),Spring对基于JMS的消息的丰富支持。 下面的接口可同时用在服务端和客户端。

package com.foo; 

public interface CheckingAccountService { 

    public void cancelAccount(Long accountId); 

} 

对于上面接口的使用在服务的端简单实现如下:

package com.foo; 

public class SimpleCheckingAccountService implements CheckingAccountService { 

    public void cancelAccount(Long accountId) { 
        System.out.println("Cancelling account [" + accountId + "]"); 
    } 

} 

这个包含JMS设施的bean的配置文件可同时用在客户端和服务端: <?xml version=”1.0″ encoding=”UTF-8″?>

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd"> 

    <bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"> 
        <property name="brokerURL" value="tcp://ep-t43:61616"/> 
    </bean> 

    <bean id="queue" class="org.apache.activemq.command.ActiveMQQueue"> 
        <constructor-arg value="mmm"/> 
    </bean> 

</beans> 

24.6.1 服务端配置

在服务端你只需要使用JmsInvokerServiceExporter来暴露服务对象。

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd"> 

    <bean id="checkingAccountService" 
            class="org.springframework.jms.remoting.JmsInvokerServiceExporter"> 
        <property name="serviceInterface" value="com.foo.CheckingAccountService"/> 
        <property name="service"> 
            <bean class="com.foo.SimpleCheckingAccountService"/> 
        </property> 
    </bean> 

    <bean class="org.springframework.jms.listener.SimpleMessageListenerContainer"> 
        <property name="connectionFactory" ref="connectionFactory"/> 
        <property name="destination" ref="queue"/> 
        <property name="concurrentConsumers" value="3"/> 
        <property name="messageListener" ref="checkingAccountService"/> 
    </bean> 

</beans> 
package com.foo; 

import org.springframework.context.support.ClassPathXmlApplicationContext; 

public class Server { 

    public static void main(String[] args) throws Exception { 
        new ClassPathXmlApplicationContext(new String[]{"com/foo/server.xml", "com/foo/jms.xml"}); 
    } 

} 

24.6.2 客户端配置

客户端只需要创建一个客户端代理来实现上面的接口(CheckingAccountService)。根据后面的bean定义创建的结果对象可以被注入到其它客户端对象中,而这个代理会负责通过JMS将调用转发到服务端。

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd"> 

    <bean id="checkingAccountService" 
            class="org.springframework.jms.remoting.JmsInvokerProxyFactoryBean"> 
        <property name="serviceInterface" value="com.foo.CheckingAccountService"/> 
        <property name="connectionFactory" ref="connectionFactory"/> 
        <property name="queue" ref="queue"/> 
    </bean> 

</beans> 
package com.foo; 

import org.springframework.context.ApplicationContext; 
import org.springframework.context.support.ClassPathXmlApplicationContext; 

public class Client { 

    public static void main(String[] args) throws Exception { 
        ApplicationContext ctx = new ClassPathXmlApplicationContext( 
                new String[] {"com/foo/client.xml", "com/foo/jms.xml"}); 
        CheckingAccountService service = (CheckingAccountService) ctx.getBean("checkingAccountService"); 
        service.cancelAccount(new Long(10)); 
    } 

}