Spring的远程访问支持
RMI:RMI是J2SE的一部分,用来创建分布式应用。Spring对RMI的支持可以减少公开和访问RMI服务的代码量,同时还帮我们处理了RMI中的大多数繁文缛节,如RemoteException的处理等。Spring还集成了RMI和JNDI,这对于CORBA服务的公开和访问来说用处是非常大的。
JAX-RPC(web服务):即“Java API for XML-based Remote Procedure Calls”,他为访问和公开RPC风格的SOAP Web服务提供了标准的Java API。Spring提供了支持类以简化JAX-RPC客户端应用的创建和基于Servlet的服务端点的创建。就像很多Java XML API一样,JAX-RPC也拥有很多实现,其中最流行的是Apache Axis,他是完全兼容于JAX-RPC的SOAP栈。本章的JAX-RPC示例将使用Axis实现。
JAX-WS(web服务):JAX-WS 2.0是JAX-RPC的 1.1的继任者。他提供了用于公开和访问SOAP 1.2Web服务及创建客户端应用的API。本章 的JAX0WS示例将使用XFire实现。
HTTP Invoker:HTTP Invoker架构是Spring的本地远程架构,他使用标准的Java序列化和HTTP为远程组件的构建提供了简单的解决方案。HTTP Invoker使用服务器端的Servlet容器来存放远程服务。这么做的好处是可以使用HTTP认证方法增强远程服务的安全性。
Hessian:Hessian是有Caucho创建的一个二进制协议,用以简化Web服务的创建。他特定于任何特定的传输方式,但通常使用HTTP。 Spring为其提供了支持类以简化Hessian服务的创建,他使用HTTP进行传输并提供了代理支持,这样就可以透明的访问Hessian服务了。
Burlap:Burlap也是由Caucho创建的,他是一个基于XML的协议,对Hessian协议是个补充。除了协议的细节之外,Burlap的使用方式与Hessian一样。Spring对Burlap的支持与对Hessian的支持差不多,事实上,在需要交换这两个协议时,Burlap类可以轻松替换掉Hessian类。
Java消息服务(JMS):JMS API是一种消息发送标准—允许Java应用程序异步地创建、发送、接收和处理消息。它提供了松耦合的和可靠的分布式通信。默认情况下,JMS Remoting使用Java串行化,但是一个JMS提供者(例如,WebLogic JMS或JBossMQ)能够使用另外一个不同的机制(例如XStream API)以便允许通过其它技术实现消息发送。
框架 | 优点 | 缺点 |
RMI | 全面支持Java对象串行化。因此,你能够通过网络发送复杂数据类型。 | RMI仅是一种Java到Java型远程方案。如果你拥有任何非Java客户端的话,那么你无法使用它。另外,你还无法通过HTTP协议存取对象,除非你有专门的“通道”实现RMI通讯。注意,它需要一个RMI编译器(为了生成代理和框架)和一个外部注册表(用于查询服务)。 |
Hessian/Burlap | 跨防火墙工作良好 | 它们使用一种专利对象串行化机制。其中,Burlap仅支持Java客户端。它们能够串行化Hibernate对象,但是对集合对象执行“惰式”加载。 |
HTTP Invoker | 基于HTTP的Java到Java Remoting;通过HTTP实现Java串行化;容易建立。 | 服务器和客户端应用程序都需要使用Spring。 仅是一种Java方案。 |
EJB | 支持Remoting J2EE服务,应用程序安全以及事务处理 | EJB是一种重量级技术。它要求使用一个J2EE容器。 |
Web服务 | 平台和语言独立 | 要付出SOAP操作所带来的开销,并且要求使用一个Web服务引擎。 |
spring对rmi的支持
Java中的CORBA支持也可以通过接口定义语言(interface definition language,IDL)来实现。
IDL是一种声明性语言,可以创建彼此交互的对象---这些对象可能是不同的编程语言所创建的。
然而当前RMI在Java中使用的更广泛,这是由于其更好的安全性和垃圾收集能力。
构建RMI服务,通常你需要为服务定义一个接口,该接口继承自java.rmi.Remote接口。然后你的RMI服务需要实现该接口,最好还继承java.rmi.server.UnicastRemoteObject类。
Spring Remoting,通过RmiServiceExporter类简化上面的操作。
package spring.senssic.rmi;
public interface Ihelloword {
public void say();
}
package spring.senssic.rmi;
public class ImplHelloworld implements Ihelloword {
@Override
public void say() {
// TODO Auto-generated method stub
System.out.println("Hello world!");
}
}
在spring的xml文件中配置rmi
<bean id="helloworldser" class="spring.senssic.rmi.ImplHelloworld"></bean>
<bean id="service" class="org.springframework.remoting.rmi.RmiServiceExporter">
<!-- 服务名 -->
<property name="serviceName" value="HelloWorldSer"></property>
<property name="service" ref="helloworldser"></property>
<property name="serviceInterface" value="spring.senssic.rmi.Ihelloword"></property>
<!-- rmi registry端口号 -->
<property name="registryPort" value="9000"></property>
<!-- 用户通讯服务端口 -->
<property name="servicePort" value="9001"></property>
</bean>
然后打包放入jboss或tomcat中运行web项目
就像所有的代理生成器一样,RMI代理生成器也实现了FactoryBean接口,这样我们就可以通过声明的方式创建并配置代理,然后将其做为依赖注入到组件中了。
package spring.senssic.rmi;
import spring.senssic.rmi.Ihelloword ;
public class HelloWorldClient {
private Ihelloword helloWorldService;
public void setHelloWorldService(Ihelloword helloWorldService) {
this.helloWorldService = helloWorldService;
}
public void run(){
helloWorldService.say();
}
}
spring配置文件,客户端,用于访问rmi服务并获取代理对象
<bean id="helloWorldService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<!-- 指向了RMI服务上的代理 -->
<property name="serviceUrl" value="rmi://localhost:9000/HelloWorld" />
<!-- 告诉代理生成器生成的接口应该实现哪个接口 -->
<property name="serviceInterface" value="spring.senssic.rmi.Ihelloword"/>
</bean>
<bean id="helloWorldClient" class="spring.senssic.rmi.HelloWorldClient">
<property name="helloWorldService" ref="helloWorldService" />
</bean>
spring对jms的支持
package spring.senssic.jms;
import javax.jms.JMSException;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
public class Sender {
private JmsTemplate jTemplate;
// 由sping注入
public void setjTemplate(JmsTemplate jTemplate) {
this.jTemplate = jTemplate;
}
public void send(final String text) {
System.out.println(text);
jTemplate.send(new MessageCreator() {
@Override
public javax.jms.Message createMessage(
javax.jms.Session paramSession) throws JMSException {
// TODO Auto-generated method stub
return paramSession.createTextMessage(text);
}
});
}
}
发送端的springxml文件配置:
<!-- jms发送 -->
<bean id="jmsConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="QueueConnectionFactory"/><!--此处的QueueConnectionFactory为全局的jndi名称,不能随意更改由jms的各个实现厂商默认提供-->
</bean>
<bean id="jmsQueue" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jms/queue"/>
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="jmsConnectionFactory"/>
<property name="defaultDestination" ref="jmsQueue"/>
</bean>
<bean id="sender" class="spring.senssic.jms.Sender">
<property name="jTemplate" ref="jmsTemplate"/>
</bean>
发送端打包项目放到jboss或weblogic中运行发送一串字符串
package spring.senssic.jms;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
public class Revice implements MessageListener {
@Override
public void onMessage(Message arg0) {
if (arg0 instanceof TextMessage) {
TextMessage tMessage = (TextMessage) arg0;
try {
System.out.println("收到消息" + tMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}
接受端xml配置:
<!-- jms接收 -->
<bean id="jmsConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="QueueConnectionFactory"/>
</bean>
<bean id="jmsQueue" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jms/queue"/>
</bean>
<bean id="receiver" class="spring.senssic.jms.Revice"/>
<bean id="listenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="jmsConnectionFactory"/>
<property name="destination" ref="jmsQueue"/>
<property name="messageListener" ref="receiver"/>
</bean>
自动转换消息
大多时候,除了简单的TextMessage外,需要发送消息都应当被封装在Java类中,例如,一个电子邮件消息应该通过一个MailMessage对象来表示。通常,ObjectMessage可以自动实现Java对象的序列化,不过,很多时候仍需要将消息以BytesMessage等其他形式发送,为此,Spring提供了一个MessageConverter接口来方便地实现Java类和JMS消息的转化。
public interface MessageConverter{
Object fromMessage(Message message);
Message toMessage(Object object,Session session);
}
同时,Spring内置的SimpleMessageConverter已经能够满足大多数消息的转化,它支持String和TextMessage、byte[]和ByteMessage,以及Map和MapMessage之间的转化。要在发送消息时自动将Java对象转化为消息,可以调用JmsTemplate的convertAndSend()。JmsTemplate默认使用SimpleMessageConverter作为默认的MessageConverter,要编写一个自定义的MessageConverter也是极其容易的,这里不再给出示例代码。