Hessian 与 Session
作者:终南 <li.zhongnan@hotmail.com>
1. ServiceContext
ServiceContext 代表为 Hessian 客户端提供服务的上下文环境,用来处理与客户端请求有关的信息。在最简单和常用的应用中,在服务器端可以通过 ServiceContext 来获取代表客户端的 ServletRequest (在 HTTP 环境中为 HttpServletRequest),因此就可以知道客户端的相关信息,如客户端的 IP 地址、端口、Header和用户名等,重要的是可以获取到代表会话的 Session 对象。
代码举例:
package example;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import com.caucho.services.server.ServiceContext;
public class BasicService implements Basic {
public String hello(String name) {
System.out.println("======== hello ========\n");
HttpServletRequest req = (HttpServletRequest) ServiceContext
.getContextRequest();
req.getSession().setAttribute("port", 1000);
System.out.println("getRemoteAddr() = " + req.getRemoteAddr());
System.out.println("getRemotePort() = " + req.getRemotePort());
System.out.println("getRemoteUser() = " + req.getRemoteUser());
System.out
.println("getSession().getId() = " + req.getSession().getId());
for (Enumeration<String> e = req.getHeaderNames(); e.hasMoreElements();) {
String headerName = e.nextElement();
System.out.println(headerName + " = " + req.getHeader(headerName));
}
return "Hello, " + name;
}
}
在上面的示例中,通过 ServiceContext 的静态方法 getContextRequest() 获取代表客户端请求的 HttpServletRequest 对象,然后就可以像普通 Web 编程那样使用 Request 和 Session 对象了。
2. Hessian 中 Sessian 的问题
一般来说,RPC 或 Web Service 这类的应用都是无状态的,但是有些应用则需要有状态的远程调用,比如先登录认证,然后再执行其他操作。
Hessian 本身也没有对有状态的应用提供直接支持。查看 HessianProxy 的代码可以发现,每次发送请求的时候,Hessain 都会调用 HessianProxyFactory 类的 openConnection 重新打开连接,并且在远程调用完成后关闭连接。
重新打开连接
protected URLConnection sendRequest(String methodName, Object []args)
throws IOException
{
URLConnection conn = null;
conn = _factory.openConnection(_url);
boolean isValid = false;
try {
// Used chunked mode when available, i.e. JDK 1.5.
if (_factory.isChunkedPost() && conn instanceof HttpURLConnection) {
try {
HttpURLConnection httpConn = (HttpURLConnection) conn;
httpConn.setChunkedStreamingMode(8 * 1024);
} catch (Throwable e) {
}
}
addRequestHeaders(conn);
OutputStream os = null;
try {
os = conn.getOutputStream();
} catch (Exception e) {
throw new HessianRuntimeException(e);
}
if (log.isLoggable(Level.FINEST)) {
PrintWriter dbg = new PrintWriter(new LogWriter(log));
os = new HessianDebugOutputStream(os, dbg);
}
AbstractHessianOutput out = _factory.getHessianOutput(os);
out.call(methodName, args);
out.flush();
isValid = true;
return conn;
} finally {
if (! isValid && conn instanceof HttpURLConnection)
((HttpURLConnection) conn).disconnect();
}
}
关闭连接
public Object invoke(Object proxy, Method method, Object []args)
throws Throwable
{
...
conn = sendRequest(mangleName, args);
if (conn instanceof HttpURLConnection) {
httpConn = (HttpURLConnection) conn;
int code = 500;
try {
code = httpConn.getResponseCode();
} catch (Exception e) {
}
parseResponseHeaders(conn);
...
try {
if (httpConn != null)
httpConn.disconnect();
} catch (Exception e) {
log.log(Level.FINE, e.toString(), e);
}
}
}
在登录认证的应用中,在调用登录认证的方法后执行其他业务操作时,需要对用户是否登录进行验证,由于 Hessian 每次调用都会重新打开和关闭连接,因此每次调用都是一个新的 Session,前面是否登录的信息就不能获取到。
3. 扩展 Hessian 的客户端程序实现对 Sessian 的支持
HTTP 是一个无状态的协议,其状态的实现是通过 Cookie 来实现的,根据 HTTP 的这个特点,我们可以在 Hessian 客户端首次调用后的每次调用中,将首次调用得到的 Cookie 添加到 HTTP Header 中,从而模拟出有状态的 HTTP 连接。
通过查看 HessianProxy 类的代码发现,其中有两个没有实现内容方法,可以获取服务器端返回的头信息 和设置发送给服务器端的 HTTP 请求头信息:
/**
* Method that allows subclasses to parse response headers such as cookies.
* Default implementation is empty.
* @param conn
*/
protected void parseResponseHeaders(URLConnection conn) {
}
/**
* Method that allows subclasses to add request headers such as cookies.
* Default implementation is empty.
*/
protected void addRequestHeaders(URLConnection conn) {
}
在使用 Hessian 进行远程调用时,addRequestHeaders 方法在 sendRequest 时调用,parseResponseHeaders 在成功发送请求后调用。因此我们可以扩展 HessianProxy 类,重新实现这两个方法,在首次调用时获取 Cookie 新,在随后的调用中 将 Cookie 添加到请求头信息中。
除了重新实现 HessianProxy 类外,还需要重新实现 HessianProxyFactory 类的 public Object create(Class api, String urlName, ClassLoader loader) 方法,以便让 HessianProxyFactory 使用重新实现的 HessianProxy 类。
重新实现的代码:
package example;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import com.caucho.hessian.client.HessianProxy;
import com.caucho.hessian.client.HessianProxyFactory;
import com.caucho.hessian.io.HessianRemoteObject;
public class MyHessianProxyFactory extends HessianProxyFactory {
@Override
public Object create(Class api, String urlName, ClassLoader loader)
throws MalformedURLException {
if (api == null)
throw new NullPointerException(
"api must not be null for HessianProxyFactory.create()");
InvocationHandler handler = null;
URL url = new URL(urlName);
handler = new MyHessianProxy(url, this);
return Proxy.newProxyInstance(loader, new Class[] { api,
HessianRemoteObject.class }, handler);
}
}
class MyHessianProxy extends HessianProxy {
/** Variable for saving cookie list */
private List<String> cookies = null;
public MyHessianProxy(URL url, HessianProxyFactory factory) {
super(url, factory);
}
/** Get cookie list from the headers of response */
@Override
protected void parseResponseHeaders(URLConnection conn) {
List<String> _cookies = conn.getHeaderFields().get("Set-Cookie");
if (_cookies != null)
cookies = _cookies;
}
/** Add cookie list to request headers*/
@Override
protected void addRequestHeaders(URLConnection conn) {
if (cookies != null) {
for (String cookieString : cookies) {
conn.setRequestProperty("Cookie", cookieString);
}
}
}
}
4. 应用举例
接口:
package example;
import java.util.List;
public interface Basic {
public boolean login(String user, String password);
public int giveMeMoney();
public void increaseMyMoney() throws Exception;
}
实现接口的服务:
package example;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import com.caucho.services.server.ServiceContext;
public class BasicService implements Basic {
public boolean login(String user, String password) {
HttpServletRequest req = (HttpServletRequest) ServiceContext
.getContextRequest();
if (user.equals("user") && password.equals("password"))
{
req.getSession().setAttribute("user", user);
return true;
}
return false;
}
public int giveMeMoney()
{
HttpServletRequest req = (HttpServletRequest) ServiceContext
.getContextRequest();
if(req.getSession().getAttribute("user") != null)
return 1000;
return 0;
}
public void increaseMyMoney() throws Exception
{
HttpServletRequest req = (HttpServletRequest) ServiceContext
.getContextRequest();
if(req.getSession().getAttribute("user") != null)
{
System.out.println(req.getSession().getAttribute("user") + "'s money increased!!!");
}
else
throw new Exception("Invalid User");
}
}
客户端程序:
package example;
import java.net.MalformedURLException;
import com.caucho.hessian.client.HessianProxyFactory;
public class BasicClient {
public static void main(String []args) throws MalformedURLException
{
String url = "http://127.0.0.1:8080/hproj/hello";
HessianProxyFactory factory = new MyHessianProxyFactory();
factory.setUser("tomcat");
factory.setPassword("tomcat");
Basic basic = (Basic) factory.create(Basic.class, url);
try {
basic.increaseMyMoney();
} catch (Exception e) {
System.out.println("ERROR: " + e.getMessage());
}
basic.login("user", "password");
System.out.println(basic.giveMeMoney());
try {
basic.increaseMyMoney();
} catch (Exception e) {
System.out.println("ERROR: " + e.getMessage());
}
}
}
在客户端程序中,不在使用原来的 HessianProxyFactory, 而是使用重新实现的 MyHessianProxyFactory 类。
分享到:
相关推荐
当我们谈论“Hessian与Spring整合”时,通常是指将Hessian作为服务通信的机制,结合Spring框架来构建分布式服务系统。这种整合有以下几个关键点: 1. **服务提供者(Service Provider)**:首先,我们需要在服务端...
在将Hessian与Spring进行整合时,我们需要确保引入了正确的jar包。这些jar包通常包括以下几个核心组件: 1. **Hessian库**:这是实现Hessian RPC的基础,包含了序列化和反序列化的类以及远程调用的相关接口。主要的...
当我们将Hessian与Spring进行整合时,主要目标是利用Spring的依赖注入(Dependency Injection, DI)和组件管理能力来简化Hessian服务的创建和管理。以下是一些关键知识点: 1. **Spring核心模块**(spring-core-...
**Hessian:深入理解与应用** Hessian是一种二进制Web服务协议,它由Caucho Technology公司开发,主要用于提供轻量级、高效的远程方法调用(Remote Method Invocation,RMI)服务。Hessian的目标是简化分布式系统...
当Hessian与Spring框架结合时,步骤稍有不同: 1. **依赖和接口**:同样需要引入Hessian库,并定义服务接口。但此时,接口的实现可以是普通的Plain Old Java Objects (POJOs)。 2. **Spring配置**:在服务端的...
3. **Python中的Hessian**:Python也有对应的Hessian库,如`pyhessian`,它实现了Hessian协议,使得Python应用能够与Java Hessian服务进行通信。同样,服务端可以通过定义Python函数并包装为Hessian服务,客户端则...
比如,如果项目依赖于旧的API或者需要与旧系统兼容,那么Hessian3.1.6可能是合适的选择。如果追求更高的性能和安全性,那么Hessian4.0.7可能更优。在实际应用中,理解每个版本的特点和改进,能够帮助我们做出明智的...
Hessian是一种二进制Web服务协议,由Caucho Technology公司开发,主要用于提供轻量级、高效的远程方法调用(Remote Method Invocation, RMI)机制。它结合了HTTP协议的可扩展性和Java序列化机制的易用性,使得在...
在图像处理领域,多尺度Hessian滤波器是一种高级的图像增强技术,它主要用于检测图像中的线性结构,特别是对于微弱或者噪声较大的图像特征有很好的识别能力。这个技术是基于数学形态学的Hessian矩阵理论,由V.S. ...
与常见的基于XML的RPC协议相比,Hessian采用二进制格式,数据传输更紧凑,解析速度更快,减少了网络带宽的消耗。 Hessian的核心是其序列化和反序列化机制。序列化是将Java对象转换为二进制流的过程,而反序列化则是...
文件"基于Hessian矩阵增强的心血管分割"可能包含了实现这一方法的详细步骤、算法描述、实验结果以及与其他方法的比较。通过这样的技术,可以精确地分割出冠状动脉血管,帮助医生更准确地诊断和治疗心血管疾病,从而...
- Java客户端会通过Hessian库与服务器端建立连接,调用服务端暴露的方法。 - 客户端代码需要知道服务器的URL以及要调用的服务接口。Hessian库会自动处理序列化和反序列化,使得客户端可以像调用本地方法一样调用...
6. **安全性与优化**: - 虽然Hessian协议效率高,但其默认的二进制格式并不适合直接查看,因此在调试时可能需要开启日志或使用特殊的查看工具。 - 为了安全,可以考虑对传输的数据进行加密,或者启用HTTPS。 ...
与基于XML的SOAP相比,Hessian的性能更高,因为XML解析和生成的开销较大。Hessian支持两种主要的调用类型:HTTP GET和HTTP POST,以及HTTP之外的TCP/IP连接。 **Spring与Hessian的集成** 在Spring中集成Hessian,...
9. **监控与日志**: 对Hessian服务的监控和日志记录是必要的,可以帮助开发者了解服务运行状态,快速定位和解决问题。可以使用各种监控工具,如JMX、Prometheus或ELK栈等。 10. **测试**: 在实际部署前,需要对...
- Hessian服务的URL需要与服务器上的部署路径匹配。 - 确保服务端和客户端的环境一致,包括JDK版本、Hessian库版本等。 - 考虑安全性问题,Hessian默认不加密传输,可以通过HTTPS或自定义Filter增强安全性。 通过...
总的来说,这个项目展示了如何将 SpringMVC 的强大 MVC 模式与 Hessian 的高效远程调用相结合,实现了一种分布式服务架构。开发者可以通过阅读 Readme 文件,了解具体的配置和使用方法,从而在自己的项目中应用这一...
在Android应用中,Hessian被用来实现客户端与服务器之间的通信,特别是处理数据请求和响应。 在“Hessian android客户端异步请求访问包”中,我们关注的核心是异步请求。在Android上,由于UI线程是负责渲染界面和...
5. **安全特性**:尽管Hessian协议本身不包含安全机制,但它可以与HTTPS结合使用,确保数据传输的安全性。 学习和研究Hessian源代码,可以帮助我们理解以下内容: - 如何实现高效的二进制序列化和反序列化算法。 -...
二、hessian-4.0.33.jar的组件与功能 hessian-4.0.33.jar是Hessian框架的一个版本,包含了实现Hessian协议的类库,用于创建和解析Hessian二进制流。它主要包括以下组件: 1. Hessian编解码器:提供对Hessian二进制...