一、概念
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框架的应用。
既然是通过HTTP请求调用,那么客户端肯定需要一个代理用于帮忙发送HTTP请求,帮忙做对象系列化和反系列化等,Spring框架中的HttpInvokerProxyFactoryBean
类处理这些杂事;
而服务器端需要一个HTTP请求处理器,帮忙处理HTTP请求已经对象系列化和反系列化工作,Spring框架中的HttpInvokerServiceExporter
类就是干这活的,对于Sun JRE 6 的HTTP Server,Spring还提供了SimpleHttpInvokerServiceExporter
类供选择。
二、服务端(服务提供者)
项目都是创建spring mvc项目
具体spring mvc创建流程
可浏览博主之前发布的文章
spring MVC项目的搭建
2.1 创建对外暴露的服务接口及对象
对外暴露的服务接口及对象都是需要打包成jar给客户端调用
所以一般来说,这种接口跟对象都是单独创建成一个项目
服务端跟客户端都直接导入jar进行使用
如果不想打包成jar使用
则客户端及服务端的接口及对象的包名、类名、需实现序列化都一样
person
对象类
package com.service;
import java.io.Serializable;
public class Person implements Serializable {
private static final long serialVersionUID = 6139752933642464599L;
private String name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
IPersonService
服务接口类
package com.service;
public interface IPersonService {
Person findByName(String name);
}
2.2 服务实现类
PersonService
实现接口,相关业务处理
这里不进行具体的数据库操作
只返回模拟数据
package com.service;
public class PersonService implements IPersonService {
@Override
public Person findByName(String name) {
Person person = new Person();
person.setAge("18");
person.setName(name);
return person;
}
}
2.3 服务代理设置
服务端需要实例化HttpInvokerServiceExporter
服务注册的一个类;
并且需要设置两个属性
service
:服务实现类,也就是接口的实现类,一般都是spring的bean;serviceInterface
:服务类型,也就是服务实现类的一个接口类;
代码如下:
package com.service.util;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;
import com.service.IPersonService;
public class RemotingService extends HttpServlet {
private static final long serialVersionUID = -1017031460828010508L;
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//实例化代理服务
HttpInvokerServiceExporterserviceExporter = new HttpInvokerServiceExporter();
//获取服务的实现bean
WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();
Object service = wac.getBean("personService");
//设置属性
serviceExporter.setService(service);
serviceExporter.setServiceInterface(IPersonService.class);
serviceExporter.afterPropertiesSet();
serviceExporter.handleRequest(req, resp);
}
}
web.xml
配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>com.service.util.remoting</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/remote/*</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/springContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
springContext.xml
配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="personService" class="com.service.PersonService" />
</beans>
项目结构:
三、客户端(服务消费者)
3.1 导入服务端的jar
<dependency>
<groupId>com.xiao</groupId>
<artifactId>springMVC</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
这里我服务端名称是springMVC
服务端跟客户端项目都是Spring MVC项目,所以都直接使用maven管理jar包
使用下列命令可导入jar进maven仓库
mvn install:install-file -Dfile=jar绝对路径全称 -DgroupId=项目包名 -DartifactId=项目名称 -Dversion=版本号 -Dpackaging=jar
3.2 客户端配置
因为使用的是spring自带的远程代理,需要项目是spring项目
所以客户端直接就使用默认的一个MVC配置
web.xml
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/springContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
springContext.xml
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- 搜索spring -->
<context:component-scan base-package="com.xiao"></context:component-scan>
<!-- 视图页面配置 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
3.3 远程代理测试
客户端也需要实现一个代理工厂类HttpInvokerProxyFactoryBean
实现代理。
也有两个属性需要设置
serviceInterface
:需要消费的服务接口类
serviceUrl
:服务提供者的url
这里url可自定义,可在路径后加上调用的接口名
服务端也就能根据接口名实现不同的代理
测试类代码:
package com.xiao.controller;
import org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean;
import org.springframework.stereotype.Controller;
import com.service.IPersonService;
import com.service.Person;
public class controller {
public static void main(String[] args) {
String name = "小小";
Person person = getService(IPersonService.class).findByName(name);
assert person.getName().equals(name) : name + "与代理返回数据name不匹配";
System.out.println(person.getName());
}
public static <T> T getService(Class<T> clazz) {
HttpInvokerProxyFactoryBean bean = new HttpInvokerProxyFactoryBean();
bean.setServiceInterface(clazz);
String url = "http://192.168.0.161:8081/springMVC/remote";
bean.setServiceUrl(url);
bean.afterPropertiesSet();
Object result = bean.getObject();
return (T) result;
}
}
运行后控制台可以输出person的name
测试通过
客户端项目结构
结语
对您有帮助请帮忙点个赞
有疑问可留言评论,博主看到会进行回复
相互学习