Spring Http Invoker使用简介

一、Spring HTTP Invoker简介

    Spring HTTP invoker 是 spring 框架中的一个远程调用模型,执行基于 HTTP 的远程调用(意味着可以通过防火墙),并使用 java 的序列化机制在网络间传递对象。这需要在远端和本地都使用Spring才行。客户端可以很轻松的像调用本地对象一样调用远程服务器上的对象,这有点类似于 webservice ,但又不同于 webservice ,区别如下:

WebService Http Invoker
跨平台,跨语言 只支持 java 语言
支持 SOAP ,提供 wsdl 不支持
结构庞大,依赖特定的 webservice 实现,如 xfire等 结构简单,只依赖于 spring 框架本身

    说明:

    1. 服务器端:通过 HTTP invoker 服务将服务接口的某个实现类提供为远程服务

    2. 客户端:通过 HTTP invoker 代理向服务器端发送请求,远程调用服务接口的方法

    3. 服务器端与客户端通信的数据均需要序列化

二、配置服务器端和客户端的步骤

配置服务器端

1. 添加 springJAR 文件

2. 创建相应的DTO(如果需要用到的话)

3. 创建服务接口

4. 创建服务接口的具体实现类

5. 公开服务

配置客户端

1. 添加 springJAR 文件

2. 创建相应的DTO(如果需要用到的话)

3. 创建服务接口

4. 访问服务

三、实例讲解

配置服务器端

先来个项目结构图:

1). 添加 springJAR 文件,这就不用说了,直接照着图片添加相应的类库。

2). 创建服务接口和相应的DTO(Data Transmission Object)

这里我们需要调用远端的服务来查询一个User对象,因此需要DTO啦。下面这个User类就是用于在网络中传输的POJO类,也就是DTO啦,因此需要实现Serializable接口:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

package com.abc.invoke.bean;

 

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 int getAge() {

        return age;

    }

     

    public void setAge(int age) {

        this.age = age;

    }

     

    public String getName() {

        return name;

    }

     

    public void setName(String name) {

        this.name = name;

    }

     

    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 + "]";

    }

}

3). UserService是一个接口,里面定义了服务的方法,这里面的方法将会被客户端调用:

?


1

2

3

4

5

6

7

package com.abc.invoke.server.service;

 

import com.abc.invoke.bean.User;

 

public interface UserService {

    public User getUserbyName(String name);

}

4). 创建服务接口的具体实现类。这里的UserServiceImpl是实现了UserService方法:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

package com.abc.invoke.server.service.impl;

 

import com.abc.invoke.bean.User;

import com.abc.invoke.server.service.UserService;

 

public class UserServiceImpl implements UserService {

    public User getUserbyName(String name) {

        User u = new User();

        u.setName(name);

        u.setEmail("abc@abc.com");

        u.setAge(20);

        return u;

    }

}

这里面我没有写DAO等层面的东西,因为那些不是这篇文章要讲述的内容,因而我只是简单的将传给服务端的参数封装到对象里的一个字段就返回了。

5). 公开服务

下面是web.xml文件的内容:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

<?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/javaee 

    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

    <display-name>SpringInvoke</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>

这里我们使用/service作为service的前缀,那么客户端请求调用时需要加上这个前缀,比如:

http://{host}:{port}/InvokeServer/service/{serviceName}

里面用到的service-servlet文件:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

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

 

    <!-- Announce that this interface is a HTTP invoker service. -->

    <bean id="userServiceInvoker" 

        class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">

        <property name="service" ref="userServiceImpl" />

        <property name="serviceInterface" value="com.abc.invoke.server.service.UserService" />

    </bean>

    <bean id="userServiceImpl" class="com.abc.invoke.server.service.impl.UserServiceImpl" />

</beans>

注意:

  1. <prop key="/userService">userServiceInvoker</prop>中的/userService是请求的服务的URL中的一部分,就是说这样的URL会被userServiceInvoker处理
  2. 这里将com.abc.invoke.server.service.UserService映射给了com.abc.invoke.server.service.impl.UserServiceImpl类了。

到此为止,服务器算是配置好了,接下来开始配置客户端。

配置客户端

先来看看项目结构图:

1). 添加 springJAR 文件,这也不用说了,直接照着图片添加相应的类库。

2). 创建服务接口和相应的DTO。

特别注意:这个类和Server端声明的DTO要一样,包名和字段名都要一样才行。因为客户端发起请求查询User,服务端处理后先将User序列化后在返回给客户端,而客户端拿到这个User后需要将其反序列化。如果包名或者字段名不同,则会被认为是不同的对象,会反序列化失败,调用也就出错了。我之前就是将User类的包名写得不一样(User类的包名在服务端为com.abc.invoke.server.bean,而在客户端则为com.abc.invoke.client.bean),报了以下错误:

?


1

2

3

4

5

6

7

8

9

Exception in thread "main" org.springframework.remoting.RemoteAccessException: 

    Could not deserialize result from HTTP invoker remote service [http://localhost:8080/InvokeServer/service/userService]; 

    nested exception is java.lang.ClassNotFoundException: com.abc.invoke.server.bean.User

    at org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor.convertHttpInvokerAccessException(HttpInvokerClientInterceptor.java:208)

    at org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor.invoke(HttpInvokerClientInterceptor.java:145)

    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)

    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)

    at com.sun.proxy.$Proxy0.getUserbyName(Unknown Source)

    at com.abc.invoke.client.Test.main(Test.java:14)

很明显可以看出,Could not deserialize result from HTTP invoker remote service......,就是因为Server端与Client端的DTO的包名不同导致反序列化失败。

3). 创建服务接口

这也没啥好说的,接口和Server端定义的一样就行,不一样肯定报错。可以直接将DTO和接口定义的类拷贝到客户端即可。这个接口将会被看做是客户端和服务端通信的“契约”。

4). 访问服务

来看看application-context.xml:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

<?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 的服务 -->

    <bean id="userService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean" >

        <property name="serviceUrl" value="http://localhost:8080/InvokeServer/service/userService"/>

        <property name="serviceInterface" value="com.abc.invoke.client.service.UserService" />

    </bean>

     

</beans>

这里使用了org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean这个类来作为一个service的代理类。注意到serviceUrl属性为http://localhost:8080/InvokeServer/service/userService (当然,我在本机启动的服务端并在本机通过main函数调用service,我在另一台机器上运行Test类的main函数,调用结果正确)。这个localhost:8080应改为实际的IP地址和端口。),这个URL的地址以/service开始,因此会被Server端拦截下来,而URL中的 /userService则为service路径,该路径与在Server端中service-servlet.xml中声明的

?


1

<prop key="/userService">userServiceInvoker</prop>

路径一致,因此这个调用会被userServiceInvoker处理。

最后再写一个简单的测试类Test.java:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

package com.abc.invoke.client;

 

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

 

import com.abc.invoke.bean.User;

import com.abc.invoke.client.service.UserService;

 

public class Test {

   public static void main(String[] args) {

       ApplicationContext ac = new ClassPathXmlApplicationContext(

                       "classpath:application-context.xml");

       UserService service = (UserService)ac.getBean("userService");

       User u = service.getUserbyName("Alvis");

       System.out.println(u);

   }

}

这个类也很简单,就是从Spring的Context中取出了定义的userService这个Bean(这其实就是服务端service的一个代理类),然后直接调用该service的方法获得结果并打印。

到此为止,客户端配置完成。

四、启动服务并测试

直接在项目InvokeServer上启动Tomcat,可以看到路径/userService的处理者是userServiceInvoker:

下面是远程调用的执行结果:

从结果中可以看到,我代码里写的名字叫Alvis,用客户端调用服务端的service后,返回的对象中名字是客户端设置的名字,测试成功。

这里是项目源代码,供需要的朋友参考。

参考页面:http://hanqunfeng.iteye.com/blog/868210

时间: 2024-10-31 02:37:31

Spring Http Invoker使用简介的相关文章

Spring 三大基础组件简介

    一,Bean,Core,Context关系   在Spring的各种组件中,Bean,Core,Context算是基础组件(ExpressionLanguage表达式支持, 这个主要就是用来支持一些spring XML配置文件表达式 和 注解中一些表达式解析,让配置有动态特性,spring早期的版本是没有这货的,不算是特别必须的, 特别核心的东西,只是为了灵活性加的),在Core container这一层构建起了整个Spring的骨骼架构.在Spring中,强调的是对Bean的管理 ,所

Spring Framework标记库简介

Spring是一个服务于所有层面的application framework:提供了bean的配置基础,AOP的支持,JDBC的提取框架,抽象事务支持,等等.它有一个非常显著的特点:在某个层面上如果你不需要Spring的支持,你就可以不使用String的class,只使用它的某一部分的功能.从它的设计理念,你可以看到String帮助你实现了真正的逻辑层和web层的分离. 相对于EJB来说,Spring是一个轻量级的J2EE应用开发框架.这里提到的轻量级指的是Spring框架本身,而不是说Spri

基于Spring实现远程服务编程

一.引言 从根本上分析,Remoting实际上是一种企业分布式计算的组件.在同一服务器(Java虚拟机)内进行调用的服务(或类)并不需要把自己暴露为一种远程服务:但是,如果你需要与一个外部程序(在不同的服务器上或在一个不同的组织中)进行通讯的话,那么,必须把它实现为一个远程服务.Spring框架为把业务类暴露为远程服务提供了一种独特而灵活的方式. Spring Remoting架构的核心是服务对象,这些对象其实是一些POJO,也称作Spring bean.Spring框架能够把这些服务对象与基础

《Spring Cloud与Docker微服务架构实战》配套代码

不才写了本使用Spring Cloud玩转微服务架构的书,书名是<Spring Cloud与Docker微服务架构实战> - 周立,已于2017-01-12交稿.不少朋友想先看看源码,现将代码放出. 本次放出的代码: 共计70+个DEMO 覆盖Eureka.Ribbon.Feign.Hystrix.Zuul.Spring Cloud Config.Spring Cloud Bus.Spring Cloud Sleuth.Docker.Docker Compose等. 1-11章代码地址: ht

spring多数据源的配置(转)

  C3P0和DBCP的区别   C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展.目前使用它的开源项目有Hibernate,Spring等.   dbcp简介:   DBCP(DataBase connection pool),数据库连接池.是 apache 上的一个 java 连接池项目,也是 tomcat 使用的连接池组件.单独使用dbcp需要3个包:common-dbcp.jar,common-pool.jar,common-co

Java+Spring+MySql环境中安装和配置MyBatis的教程_java

1.MyBatis简介与配置MyBatis+Spring+MySql 1.1MyBatis简介      MyBatis 是一个可以自定义SQL.存储过程和高级映射的持久层框架.MyBatis 摒除了大部分的JDBC代码.手工设置参数和结果集重获.MyBatis 只使用简单的XML 和注解来配置和映射基本数据类型.Map 接口和POJO 到数据库记录.相对Hibernate和Apache OJB等"一站式"ORM解决方案而言,Mybatis 是一种"半自动化"的OR

微服务基础

微服务基础篇 1: service consumer -> Proxy Server ->Load Balance -> Service Discovery -> Target Service 2: Broser curl Other -> Zuul -> Ribbon -> Euraka -> Restful API zuul: 是边缘服务,用来提供动态路由,监控,授权,安全,调度等功能,将权限控制等一些业务逻辑抽离出来,单独放到Zuul里,使得服务组件更

Spring自定义视图和视图解析器简介及开发

Spring 视图和视图解析器简介 什么是 Spring 视图和视图解析器 Spring MVC(Model View Controller)是 Spring 中一个重要的组成部分,而 Spring 视图和视图解析器则是 Spring MVC 中的组成部分.在介绍 Spring 视图和视图解析器前,我们先了解下在 Spring MVC 框架中,一个 Web 请求所需经历 的六个阶段: 请求会首先被 Spring MVC 的前端请求分发器(Dispatcher)拦截.该拦截器是一个 Servlet

Spring Cloud连载(3)Spring Boot简介与配置

本站小福利 点我获取阿里云优惠券 原文作者:杨大仙的程序空间 3 Spring Boot简介与配置   3.1 Spring Boot         Spring Cloud基于Spring Boot搭建,本小节将对Spring Boot作一个大致的讲解,读者知道Spring Boot作用即可. 3.1.1 Spring Boot简介         开发一个全新的项目,需要先进行开发环境的搭建,例如要确定技术框架以及版本,还要考虑各个框架之间的版本兼容问题,完成这些繁琐的工作后,还要对新项目