基于Spring实现的Rmi, HttpInvoker, Hessian, Web services

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kang389110772/article/details/80241828

基于Spring实现的Rmi, HttpInvoker, Hessian, Web services

因为要写Ronda的关系,所以就想了解下应该怎么实现Rmi协议。普通的Rmi必须要继承Remote
方法,但是在框架里肯定不会为每个类都继承Remote。

那么就来看看官网上怎么说的,然后再分析一下为什么这么实现就可以。

Spring使用不同的技术支持多种远程调用。目前支持四种:

  • Rmoete Method Invocation. 通过使用RmiProxyFactoryBeanRmiServiceExporter支持了传统的RMI和透明的RMI远程调用。这里说传统的是继承了Remote类和抛出异常java.rmi.RemoteException,后一种说的是只要有接口就可以。

  • Spring Http invoker. 只要类实现了接口,那么Spring就支持通过Http进行序列化传输。使用到的类是Http
    InvokerProxyFactoryBean
    HttpInvokerServiceExporter

  • Hessian. 使用HessianProxyFactoryBeanHessianServiceExporter你可以使用Hessian协议进行传输。

  • Burlap. Burlap是对于Hessian的另外一个格式选择,即XML。使用BurlapProxyFactoryBeanBurlapServiceExporter

  • JAX RPC. Spring通过JAX-RPC提供对web service的支持

  • JMS. 使用JmsInvokerServiceExporterJmsInvokerProxyFactoryBean进行实现

从上面的简介我们可以看到,Spring主要使用ServiceExporter进行服务的导出,使用ProxyFactoryBean进行生成代理的服务单对象,然后实现远程调用。

RMI

核心就是讲Service导出来,然后在客户端生成一个Service的代理对象

扫描二维码关注公众号,回复: 4725516 查看本文章

Server端:

<bean class="org.springframework.remoting.rmi.RmiServiceExporter">
    <!-- does not necessarily have to be the same name as the bean to be exported -->
    <property name="serviceName" value="AccountService"/>
    <property name="service" ref="accountService"/>
    <property name="serviceInterface" value="example.AccountService"/>
    <!-- defaults to 1099 -->
    <property name="registryPort" value="1199"/>
</bean>

Client端:

<bean id="accountService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
    <property name="serviceUrl" value="rmi://HOST:1199/AccountService"/>
    <property name="serviceInterface" value="example.AccountService"/>
</bean>

Hessian

Hessian协议使用通过HTTP进行通讯。所以使用DispatcherServlet进行暴露服务.

<servlet>
    <servlet-name>remoting</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>remoting</servlet-name>
    <url-pattern>/remoting/*</url-pattern>
</servlet-mapping>
暴露服务
<bean id="accountService" class="example.AccountServiceImpl">
  <!-- any additional properties, maybe a DAO? -->
</bean>

<bean name="/AccountService" class="org.springframework.remoting.caucho.HessianServiceExporter">
  <property name="service" ref="accountService"/>
  <property name="serviceInterface" value="example.AccountService"/>
</bean>

客户端

<bean class="example.SimpleObject">
  <property name="accountService" ref="accountService"/>
</bean>

<bean id="accountService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
    <property name="serviceUrl" value="http://remotehost:8080/remoting/AccountService"/>
    <property name="serviceInterface" value="example.AccountService"/>
</bean>

HTTP

HTTP其实是使用自己的协议进行HTTP交互,而Hessian、Burlap使用自己的序列化协议。

<bean name="/AccountService" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
  <property name="service" ref="accountService"/>
  <property name="serviceInterface" value="example.AccountService"/>
</bean>
<bean id="httpInvokerProxy" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
  <property name="serviceUrl" value="http://remotehost:8080/remoting/AccountService"/>
  <property name="serviceInterface" value="example.AccountService"/>
</bean>

Web services

使用JAX-RPC进行暴露

Spring提供一个ServletEndPointSupport类来方便进行暴露web service服务,业务层的类需要继承ServletEndpointSupport.

public class AccountServiceEndpoint extends ServletEndpointSupport implements RemoteAccountService {

    private AccountService biz;

    protected void onInit() {
        this.biz = (AccountService) getWebApplicationContext().getBean("accountService");
    }

    public void insertAccount(Account acc) throws RemoteException {
        biz.insertAccount(acc);
    }

    public Account[] getAccounts(String name) throws RemoteException {
        return biz.getAccounts(name);
    }
}

访问web service

spring有两个工厂bean用来创建web service的代理: LocalJaxRpcServiceFactoryBeanJaxRpcPortProxyFactoryBean。前面的一个类返回的JAX-RPC服务,后一个返回全面的实现业务接口的类。

<bean id="accountWebService" class="org.springframework.remoting.jaxrpc.JaxRpcPortProxyFactoryBean">
    <property name="serviceInterface" value="example.RemoteAccountService"/>
    <property name="wsdlDocumentUrl" value="http://localhost:8080/account/services/accountService?WSDL"/>
    <property name="namespaceUri" value="http://localhost:8080/account/services/accountService"/>
    <property name="serviceName" value="AccountService"/>
    <property name="portName" value="AccountPort"/>
</bean>

现在可以正常使用service,不过要处理RemoteException. 可以通过配置一个non-RMI的接口来去除。

客户端注册Bean Mappings

public class AxisPortProxyFactoryBean extends JaxRpcPortProxyFactoryBean {

   protected void postProcessJaxRpcService(Service service) {
      TypeMappingRegistry registry = service.getTypeMappingRegistry();
      TypeMapping mapping = registry.createTypeMapping();
      registerBeanMapping(mapping, Account.class, "Account");
      registry.register("http://schemas.xmlsoap.org/soap/encoding/", mapping);
   }

   protected void registerBeanMapping(TypeMapping mapping, Class type, String name) {
      QName qName = new QName("http://localhost:8080/account/services/accountService", name);
      mapping.register(type, qName,
          new BeanSerializerFactory(type, qName),
          new BeanDeserializerFactory(type, qName));
   }
}

注册自定义的Handler

public class AccountHandler extends GenericHandler {

    public QName[] getHeaders() {
        return null;
    }

    public boolean handleRequest(MessageContext context) {
        SOAPMessageContext smc = (SOAPMessageContext) context;
        SOAPMessage msg = smc.getMessage();

        try {
            SOAPEnvelope envelope = msg.getSOAPPart().getEnvelope();
            SOAPHeader header = envelope.getHeader();
            // ...

        } catch (SOAPException e) {
            throw new JAXRPCException(e);
        }

        return true;
    }
}
public class AccountHandlerJaxRpcPortProxyFactoryBean extends JaxRpcPortProxyFactoryBean {

    protected void postProcessJaxRpcService(Service service) {
        QName port = new QName(this.getNamespaceUri(), this.getPortName());
        List list = service.getHandlerRegistry().getHandlerChain(port);
        list.add(new HandlerInfo(AccountHandler.class, null, null));

        logger.info("Registered JAX-RPC Handler [" + AccountHandler.class.getName() + "] on port " + port);
    }
}
<bean id="accountWebService" class="example.AccountHandlerJaxRpcPortProxyFactoryBean">
    <!-- ... -->
</bean>
Exposing web services using XFire

添加servlet

<servlet>
  <servlet-name>xfire</servlet-name>
  <servlet-class>
    org.springframework.web.servlet.DispatcherServlet
  </servlet-class>
</servlet>
<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>
    classpath:org/codehaus/xfire/spring/xfire.xml
  </param-value>
</context-param>

<listener>
  <listener-class>
    org.springframework.web.context.ContextLoaderListener
  </listener-class>
</listener>

添加servlet mapping

<beans>

  <bean name="/Echo" class="org.codehaus.xfire.spring.remoting.XFireExporter">
    <property name="serviceInterface" value="org.codehaus.xfire.spring.Echo"/>
    <property name="serviceBean">
        <bean class="org.codehaus.xfire.spring.EchoImpl"/>
    </property>
    <!-- the XFire bean is defined in the xfire.xml file -->
    <property name="xfire" ref="xfire"/>
  </bean>

</beans>

JMS

通过JMS进行交互。 Spring支持JMS是很基本的,在同一个线程中进行通讯,不支持事务。

Server和Client都需要的接口

package com.foo;

public interface CheckingAccountService {

   void cancelAccount(Long accountId);
}

Server端实现:

package com.foo;

public class SimpleCheckingAccountService implements CheckingAccountService {

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

Server和Client都有的配置文件:

<?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-2.0.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>

Server端的配置:

<?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-2.0.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>

Client端的配置:

<?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-2.0.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>

简单说下RMI其实还是走Java的那一套,就是判断你的service有没有继承Remote接口,如果没有就给你生成一个继承的接口暴露出去。

猜你喜欢

转载自blog.csdn.net/kang389110772/article/details/80241828