Spring HttpInvoker入门 (1)

xiaoxiao2021-02-28  29

Spring HTTP Invoker简介

Hessian和Burlap都是基于HTTP的,他们都解决了RMI所头疼的防火墙渗透问题。但当传递过来的RPC消息中包含序列化对象时,RMI就完胜Hessian和Burlap了。 因为Hessian和Burlap都是采用了私有的序列化机制,而RMI使用的是Java本身的序列化机制。如果数据模型非常复杂,那么Hessian/Burlap的序列化模型可能就无法胜任了。 Spring开发团队意识到RMI服务和基于HTTP的服务之前的空白,Spring的HttpInvoker应运而生。 Spring的HttpInvoker,它基于HTTP之上提供RPC,同时又使用了Java的对象序列化机制。

使用HTTP 协议进行remoting.由于传统的RMI方式存在协议可能被拦截等问题,spring增加了http方式的remoting,也就是说使用HTTP协议取代了JRMP协议。这种方式有优点为只要防火墙允许HTTP协议即可运行。其他方面依旧使用Java平台默认的序列化方法序处理对象。由于使用了HTTP协议,服务器端需要运行在web服务器中,同时核心类HttpInvokerServiceExporter和HttpInvokerProxyFactoryBean也被放在spring-web这个jar中.

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

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

配置服务器端

创建实现Serializable接口的bean

package com.iframe.springmvc.bean; import java.io.Serializable; import java.util.Date; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import org.springframework.stereotype.Component; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @Component public class User implements Serializable{ /** * */ private static final long serialVersionUID = 1L; private int Cd; private String username; private String password; private Date birthday; private String address; public User(){ } public User(int cd, String username, String password, Date birthday, String address) { super(); Cd = cd; this.username = username; this.password = password; this.birthday = birthday; this.address = address; } public int getCd() { return Cd; } public void setCd(int cd) { Cd = cd; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "User [Cd=" + Cd + ", username=" + username + ", password=" + password + ", birthday=" + birthday + ", address=" + address + "]"; } } 创建接口及其实现类 UserService package com.iframe.springmvc.service; import java.util.Map; import com.iframe.springmvc.bean.User; public interface UserService { //通过id查询用户信息 public User searchUserById(int id) throws Exception; //检查用户是否存在 public int checkUser(User user) throws Exception; //检查用户是否存在 public int checkUser2(int id,String password) throws Exception; public int updateUser(Map<String,Object> map); } UserServiceImpl

package com.iframe.springmvc.service.impl; import java.util.Map; import javax.annotation.Resource; import org.springframework.stereotype.Service; import com.iframe.springmvc.bean.User; import com.iframe.springmvc.mapper.UserMapper; import com.iframe.springmvc.service.UserService; @Service("userService") public class UserServiceImpl implements UserService { private UserMapper userMapper; public User searchUserById(int id) throws Exception { return userMapper.findUserById(id); } public int checkUser(User user) throws Exception { return userMapper.checkUser(user); } public int checkUser2(int id, String password) throws Exception { return userMapper.checkUser2(id,password); } public int updateUser(Map<String, Object> map) { return userMapper.updateUser(map); } public UserMapper getUserMapper() { return userMapper; } @Resource(name="userMapper") //@Resource(type=UserMapper.class) public void setUserMapper(UserMapper userMapper) { this.userMapper = userMapper; } }

UserMapper 

使用mybatis 

package com.iframe.springmvc.mapper; import java.util.Map; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import com.iframe.springmvc.bean.User; @Mapper public interface UserMapper { //通过id 查询用户信息 public User findUserById(int id) throws Exception; //检查用户是否存在 方式一 public int checkUser(User user) throws Exception; //检查用户是否存在 方式二 @Param注解的作用是给参数命名,参数命名后就能根据名字得到参数值 public int checkUser2(@Param("ids") int id,@Param("password") String password) throws Exception; //向用户表中插入信息 () public int updateUser(Map<String,Object> map); }

UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- namespace接口全名 --> <mapper namespace="com.iframe.springmvc.mapper.UserMapper"> <!-- <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true" /> --> <select id="findUserById" parameterType="int" resultType="com.iframe.springmvc.bean.User"> SELECT id as Cd, username as username, password as passwrod, birthday as birthday, address as address FROM USER where id = #{cd} </select> <select id="checkUser" parameterType="com.iframe.springmvc.bean.User" resultType="int"> SELECT COUNT(*) FROM USER where id= #{cd} AND password=#{password} </select> <select id="checkUser2" parameterType="map" resultType="int"> SELECT COUNT(*) FROM USER where id= #{ids} AND password=#{password} </select> <update id="updateUser" parameterType="map"> update user set username=#{username,jdbcType=VARCHAR} where id=#{id,jdbcType=INTEGER} </update> </mapper>公开服务 使用springmvc配置

dispatcher-server.xml

<!--httpInvoker 服务器端设置 使用springmvc URL映射配置 --> <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/userService">userHttpInvokerService</prop> </props> </property> </bean> <!-- Announce that this interface is a HTTP invoker service. 宣布该接口是一个http invoker 服务--> <bean name="userHttpInvokerService" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter"> <property name="service" ref="userService"/> <property name="serviceInterface" value="com.iframe.springmvc.service.UserService"/> </bean>

org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean

org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter 原属于 spring-remoting 现整合到spring-web

配置客户端

访问服务配置 server-invoker.xml

   

<bean id="userServiceProxy" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean"> <property name="serviceUrl"> <value>http://localhost:8080/HttpInvoke/userService</value> </property> <!-- Server端与Client端的DTO的包名不同导致反序列化失败。 接口名字和bean名字保持一致 --> <!-- 如果包名或者字段名不同,则会被认为是不同的对象,会反序列化失败,调用也就出错了 --> <property name="serviceInterface"> <value>com.iframe.springmvc.service.UserService</value> </property> </bean> 注意

1.客户端配置bean 接口 及其实现类并保证和服务器端同名同包。不然会因为客户端反序列化失败(报ClassCastException异常)。Bean对象需要实现Serializable接口。

2.如果serialVersionUID是指定生成,需要保持客户端和服务端的UID保持一致

原因 :

Java的序列化机制是通过判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常,即是InvalidCastException

参考博文:

关于serialVersionUID的说明

转载请注明原文地址: https://www.6miu.com/read-2625748.html

最新回复(0)