Spring Http Invoker使用简介

Spring HTTP Invoker一种JAVA远程方法调用框架实现,原理与JDK的RMI基本一致,所以我们先跟其它JAVA远程方法调用实现做下简单比较。

  • RMI:使用JRMP协议(基于TCP/IP),不允许穿透防火墙,使用JAVA系列化方式,使用于任何JAVA应用之间相互调用。

  • Hessian:使用HTTP协议,允许穿透防火墙,使用自己的系列化方式,支持JAVA、C++、.Net等跨语言使用。

  • Burlap: 与Hessian相同,只是Hessian使用二进制传输,而Burlap使用XML格式传输(两个产品均属于caucho公司的开源产品)。

  • Spring HTTP Invoker: 使用HTTP协议,允许穿透防火墙,使用JAVA系列化方式,但仅限于Spring应用之间使用,即调用者与被调用者都必须是使用Spring框架的应用。HttpInvoke实现远程访问。Spring httpInvoker使用标准java序列化机制,通过Http暴露业务服务。客户端可以很轻松的像调用本地对象一样调用远程服务器上的对象。如果你的参数和返回值比较复杂的,通过httpInvoker有巨大的优势。

注意事项:由于是通过网络传输,所以服务端、客户端的POJO类,都要实现Serializable接口,进行序列化、反序列化。

服务端环境:Tomcat服务, Spring环境

因为服务端需要提供HTTP请求服务,而且是基于Servlet的,所以服务端需要跑在如Tomcat这样的Servlet Web容器上;
服务类只要是普通的POJO即可,没有特殊要求。

客户端环境:Spring环境

一 远程访问流程

1. 服务端定义服务接口

2. 服务端实现服务接口

3. 服务端暴露服务对象

4. 客户端定义暴露的服务端接口

5. 客户端配置服务参数

6. 测试客户端调用服务接口

Spring HTTP Invoker有两种实现方式

1.基于Url映射方式,远程系统处理请求的方式同SpringMVC的controller类似,所有的请求通过在web.xml中的 org.springframework.web.servlet.DispatcherServlet统一处理,根据url映射,去对应的 【servlet名称-servlet.xml】文件中,查询跟请求的url匹配的bean配置
2.基于Servlet方式,由org.springframework.web.context.support.HttpRequestHandlerServlet去拦截url- pattern匹配的请求,如果匹配成功,去ApplicationContext中查找name与servlet-name一致的bean,完成远程方法调用。

下面我们使用第一种方式实现测试。

二 Spring HttpInvoker具体实现

1. 服务端定义服务接口

接口1:获取当前学生对象的List集合
import java.util.List;
import com.entity.Student;

public interface StudentService {
    public List<Student> getStudent();
}
接口2:根据名字获取用户
import com.entity.User;

public interface UserService {
    public User getUserbyName(String name);
}

2. 服务端实现服务接口

实现上述接口1
import java.util.ArrayList;
import java.util.List;
import com.entity.Student;
import com.entity.User;
import com.service.StudentService;

public class StudentServiceImpl implements StudentService{
    @Override
    public List<Student> getStudent() {
        List<Student> slist = new ArrayList<>();
        Student student1 = new Student();
        Student student2 = new Student();

        User user1 = new User("zhangsan", 24, "perfectwwh@163.com");
        User user2 = new User("lisi", 25, "perfectwwh@163.com");

        student1.setUser(user1);
        student2.setUser(user2);

        slist.add(student1);
        slist.add(student2);
        return slist;
    }
}
实现上述接口2
import com.entity.User;
import com.service.UserService;

public class UserServiceImpl implements UserService{
    @Override
    public User getUserbyName(String name) {
        User user = new User();
        user.setName(name);
        user.setAge(26);
        user.setEmail("perfectwwh@163.com");
        return user;
    }
}

3. 服务端暴露服务对象

服务端的XML配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <!-- 这个Bean映射了当URL是/userService时,处理器为userServiceInvoker -->
    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/userService">userServiceInvoker</prop>
            </props>
        </property>
    </bean>
     <!-- 这个Bean映射了当URL是/studentService时,处理器为studentServiceInvoker -->
      <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
         <property name="mappings">
            <props>
                <prop key="/studentService">studentServiceInvoker</prop>
            </props>
        </property>
    </bean>


    <!-- Announce that this interface is a HTTP invoker service. -->
    <!-- 服务端暴露UserService服务接口 -->
    <bean id="userServiceInvoker" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
        <property name="service" ref="userServiceImpl" />
        <property name="serviceInterface" value="com.service.UserService" />
    </bean>
    <bean id="userServiceImpl" class="com.service.impl.UserServiceImpl" />

     <!-- 服务端暴露UserService服务接口 --> 
    <bean id="studentServiceInvoker" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
        <property name="service" ref="studentServiceImpl" />
        <property name="serviceInterface" value="com.service.StudentService" />
    </bean>
    <bean id="studentServiceImpl" class="com.service.impl.StudentServiceImpl" />
</beans>

4. 客户端定义暴露的服务端接口(和服务端接口一模一样,保持包结构一致)

接口1:获取当前学生对象的List集合
import java.util.List;
import com.entity.Student;

public interface StudentService {
    public List<Student> getStudent();
}
接口2:根据名字获取用户
import com.entity.User;

public interface UserService {
    public User getUserbyName(String name);
}

5. 客户端配置服务参数(名称为:client-application-context.xml)

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

    <!-- 客户端使用 HttpInvokerProxyFactoryBean 代理客户端向服务器端发送请求,请求接口为 UserService 的服务,
     ip地址为服务器地址 -->
    <bean id="userService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean" >
        <property name="serviceUrl" value="http://192.168.1.96:8080/SpringHttpInvokerDemo/service/userService"/>
        <property name="serviceInterface" value="com.service.UserService" />
    </bean>

     <!-- 客户端使用 HttpInvokerProxyFactoryBean 代理客户端向服务器端发送请求,请求接口为StudentService的服务,
      ip地址为服务器地址 -->
    <bean id="studentService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean" >
        <property name="serviceUrl" value="http://192.168.1.96:8080/SpringHttpInvokerDemo/service/studentService"/>
        <property name="serviceInterface" value="com.service.StudentService" />
    </bean>
</beans>

6. 客户端调用服务接口

import java.util.List;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.entity.Student;
import com.entity.User;
import com.service.StudentService;
import com.service.UserService;

public class Test {
   public static void main(String[] args) {
       ApplicationContext ac = 
       new ClassPathXmlApplicationContext("classpath:client-application-context.xml");
       UserService service = (UserService)ac.getBean("userService");
       User u = service.getUserbyName("wwh");
       System.out.println(u);
       StudentService studentService = ac.getBean("studentService", StudentService.class);
       List<Student> slist = studentService.getStudent();
       for(Student s: slist) {
           System.out.println(s);
       }
   }
}

7.客户端输出结果

这里写图片描述

POJO

注意事项:由于是通过网络传输,所以服务端、客户端的POJO类,都要实现Serializable接口,进行序列化、反序列化。
import java.io.Serializable;
public class Student implements Serializable{
    private static final long serialVersionUID = 1L;
    private User user;
    public User getUser() {
        return user;
    }
    public void setUser(User user) {
        this.user = user;
    }
    @Override
    public String toString() {
        return "Student [user=" + user + "]";
    }
}
import java.io.Serializable;
public class User implements Serializable {
     private static final long serialVersionUID = -6970967506712260305L;
     private String name;
     private int age;
     private String email;
     public User() {}
    public User(String name, int age, String email) {
        super();
        this.name = name;
        this.age = age;
        this.email = email;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    @Override
    public String toString() {
        return "User [name=" + name + ", age=" + age + ", email=" + email + "]";
    }
}

#####配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <display-name>SpringHttpInvokerDemo</display-name>

    <servlet>
        <servlet-name>service</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:service-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>service</servlet-name>
        <url-pattern>/service/*</url-pattern>
    </servlet-mapping>
    <!-- 其实下面这个welcome-file-list没啥用,我留着只是为了在起好Tomcat后不会报一个404而已 -->
    <welcome-file-list>
            <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>
依赖Spring
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>SpringHttpInvokerDemo</groupId>
  <artifactId>SpringHttpInvokerDemo</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <name>SpringHttpInvokerDemo</name>
  <description/>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <dependencies>

      <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.10.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>4.3.10.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>4.3.10.RELEASE</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/log4j/log4j -->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>

      <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.38</version>
    </dependency>

  </dependencies>
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.3.2</version>
        <configuration>
          <source>1.7</source>
          <target>1.7</target>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.2</version>
        <configuration>
          <version>3.0</version>
          <failOnMissingWebXml>false</failOnMissingWebXml>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

参考博客1
参考博客2
HttpInvoker运作原理

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值