`
lvff1314
  • 浏览: 12015 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

关于hessian中使用Session的问题

阅读更多
  本帖旨在讨论hessian的session以及cookie问题,对于hessian的使用网上和官方已经有很多例子,故不在此做讨论。
  最近在做一个项目,client面临多种平台的手机客户端以及pc浏览器的flash,在寻找rpc方案的过程中,最初选择使用phprpc,而phprpc没有Objective-c的client版本(Hprose虽有此版,但似乎收费),后转道hessian,hessian使用过程中发现,hessian的client不支持cookie机制,进而导致了其server端不支持共享session,也就是说,由于hessian使用的是http协议且client的实现不支持cookie,从而导致了client对server的每次调用都会建立一个新的session,而如果在每次调用都加入固定的类似jsessionid或userid这种参数的话,似乎看着很不爽,看到网上有篇帖子http://qieqie.iteye.com/blog/82492,看到有人使用aop在http协议层对于使用者透明的增加和剥离这个参数,本人还是觉得不爽,因为我的服务端架构中,已经确定了一个集群方案,而其中对于集群的session准备使用memcached-session-manager,从而要求我在改架构中需要使用标准的http session进行存储。
无奈之下,决定扩展hessian(我使用的是4.0.7),期间曾看到网上高手修改过较早版本的hessian(见贴http://hi.baidu.com/li_zhongnan/blog/item/37fe8ffaefe9ad17a9d31153.html),而这种方式我尝试后发现仍无法使用cookie,后发现原来新版的HessianProxy中的parseResponseHeaders方法已经被废弃使用,于是翻看源码,最后发现在HessianURLConnection(这个类可能在较早的hessian中没有)中有有了一个新的parseResponseHeaders方法,于是扩展开始,为了不修改源码,我自己新建了一个工程,并作为基础工程被我的client所引用,这里我只贴出核心部分的class代码,有兴趣的朋友可以在此基础上进一步完善:
package com.caucho.hessian.client;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;

/**
 * 
 * 
 * @author liliang
 * @descirption 为维持session而扩展的支持cookie的连接
 */
public class CookieHessianURLConnection extends HessianURLConnection {

	/**
	 * @description 共享cookie
	 */
	private static List<String> cookies = null;

	CookieHessianURLConnection(URL url, URLConnection conn) {
		super(url, conn);
	}
	
	@Override
	protected void parseResponseHeaders(HttpURLConnection conn)
			throws IOException {
		super.parseResponseHeaders(conn);
		List<String> _cookies = conn.getHeaderFields().get("Set-Cookie");
		if (_cookies != null)
			cookies = _cookies;
	}

	public void addRequestHeaders() {
		if (cookies != null) {
			for (String cookieString : cookies) {
				addHeader("Cookie", cookieString);
			}
		}
	}

}




package com.caucho.hessian.client;

import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 
 * 
 * @author liliang
 * @descirption 连接工厂类 主要使用扩展后的CookieHessianURLConnection来维持连接
 *              open方法除返回值外完全摘自源码HessianURLConnectionFactory
 */
public class CookieHessianURLConnectionFactory extends
		AbstractHessianConnectionFactory {

	private static final Logger log = Logger
			.getLogger(CookieHessianURLConnectionFactory.class.getName());

	@Override
	public HessianConnection open(URL url) throws IOException {

		if (log.isLoggable(Level.FINER))
			log.finer(this + " open(" + url + ")");

		URLConnection conn = url.openConnection();

		// HttpURLConnection httpConn = (HttpURLConnection) conn;
		// httpConn.setRequestMethod("POST");
		// conn.setDoInput(true);

		long connectTimeout = getHessianProxyFactory().getConnectTimeout();

		if (connectTimeout >= 0)
			conn.setConnectTimeout((int) connectTimeout);

		conn.setDoOutput(true);

		long readTimeout = getHessianProxyFactory().getReadTimeout();

		if (readTimeout > 0) {
			try {
				conn.setReadTimeout((int) readTimeout);
			} catch (Throwable e) {
			}
		}

		/*
		 * // Used chunked mode when available, i.e. JDK 1.5. if
		 * (_proxyFactory.isChunkedPost() && conn instanceof HttpURLConnection)
		 * { try { HttpURLConnection httpConn = (HttpURLConnection) conn;
		 * 
		 * httpConn.setChunkedStreamingMode(8 * 1024); } catch (Throwable e) { }
		 * }
		 */

		return new CookieHessianURLConnection(url, conn);

	}

}



public class MyHessianProxy extends HessianProxy {

	public MyHessianProxy(URL url, HessianProxyFactory factory, Class<?> api) {
		super(url, factory, api);
	}

	/** Add cookie list to request headers */
	@Override
	protected void addRequestHeaders(HessianConnection conn) {
		super.addRequestHeaders(conn);
		if(conn instanceof CookieHessianURLConnection) {
			CookieHessianURLConnection connection = (CookieHessianURLConnection)conn;
			connection.addRequestHeaders();
		}
		
	}

}



package com.mostar.common.hessian;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.net.URL;

import com.caucho.hessian.client.HessianProxyFactory;
import com.caucho.hessian.io.HessianRemoteObject;

public class MyHessianProxyFactory extends HessianProxyFactory {
	@Override
	public Object create(Class<?> api, URL url, ClassLoader loader) {
		if (api == null)
			throw new NullPointerException(
					"api must not be null for HessianProxyFactory.create()");
		InvocationHandler handler = null;

		handler = new MyHessianProxy(url, this, api);

		return Proxy.newProxyInstance(loader, new Class[] { api,
				HessianRemoteObject.class }, handler);
	}
}



  代码中的cookies 之所以使用了static,主要是考虑一个client公用一个session,而非早起的IE浏览器每个进程新开一个session的机制。

客户端调用例子:
		// 设置连接工厂类
		System.setProperty(HessianConnectionFactory.class.getName(),
				CookieHessianURLConnectionFactory.class.getName());
		String url = "http://10.0.8.1:8080/test/hello.service";
		MyHessianProxyFactory factory = new MyHessianProxyFactory();
		IHellowordService hellowordService = (IHellowordService) factory
				.create(IHellowordService.class, url);
		System.out.println(hellowordService.sayHello("myname"));


修改后经测试,在服务器端可以使用如下代码获取request以及session了:
		HttpServletRequest req = (HttpServletRequest) ServiceContext
				.getContextRequest();
		req.getSession();


但问题又来了,我在测试的时候发现,这种获取request及session的方法只有在使用hessian自带的HessianServlet进行服务发布才可用,而如果使用spring mvc和spring的HessianServiceExporter进行hessian的服务发布的话,那么这种获取request和session的方式仍不可用,查看spring3的源码惊奇的发现,在HessianServiceExporter以及HessianExporter的实现中,并没有像hessian的servlet那样调用ServiceContext.begin和ServiceContext.end()方法,难道是spring仔细查看hessian的源码或api,还是说spring不想让开发者拿到servlet容器相关的request和session之类的实例,但不管怎么样,我有这样的需求,于是又扩展了spring的HessianServiceExporter(3之前的版本实现可能稍有区别):
/**
 * 
 *
 * @author liliang
 * @descirption 对spring的HessianServiceExporter进行扩展,以能够在逻辑service中使用httpRequest
 */
public class HessianServiceContextExporter extends HessianServiceExporter {
	
	@Override
	public void handleRequest(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		try {
			//
			String serviceId = request.getPathInfo();
			String objectId = request.getParameter("id");
			if (objectId == null)
				objectId = request.getParameter("ejbid");

			ServiceContext.begin(request, serviceId, objectId);

			// 调用spring自身的实现
			super.handleRequest(request, response);
		} finally {
			ServiceContext.end();
		}
	}
	
}


而spring mvc的servlet配置文件中如下:
	<bean name="/hello.service"
		class="org.springframework.remoting.caucho.HessianServiceContextExporter">
		<property name="service" ref="hellowordService" />
		<property name="serviceInterface"
			value="com.mostar.sng.service.sample.IHellowordService" />
	</bean>


至此,即便我们使用spring进行发布hessian服务,通过可以通过ServiceContext获取上下文的request等信息了。
以上不论对于hessian client还是对于spring的hessian封装,都是只做增量扩展。
分享到:
评论
3 楼 lvff1314 2011-02-25  
zb7503 写道
我前段时间也在寻找session的机制。
但是后来我没有采用这么复杂的操作,直接采用是head里面设置auth签名。把需要的用户名传到服务端。


如果不使用集群中session集中管理的方案,是可以简单的将用户信息放到header里,我遇到的项目是在一个大型集群架构里,且需要使用MSM这样的中间件来集中管理session,所以不得已而实现session机制。
2 楼 may_cauc 2011-02-03  
zb7503 写道
我前段时间也在寻找session的机制。
但是后来我没有采用这么复杂的操作,直接采用是head里面设置auth签名。把需要的用户名传到服务端。

能不能详细的讲一下?
1 楼 zb7503 2011-01-27  
我前段时间也在寻找session的机制。
但是后来我没有采用这么复杂的操作,直接采用是head里面设置auth签名。把需要的用户名传到服务端。

相关推荐

    Springmvc+Hibernate+Hessian架包整合

    在IT行业中,构建高效、可扩展的Web应用是至关重要的,而Spring MVC、Hibernate和Hessian这三大技术框架的整合可以实现这一目标。本篇将详细介绍这三个组件以及它们如何协同工作,帮助开发者构建高质量的分布式应用...

    Spring-Reference_zh_CN(Spring中文参考手册)

    6.8.1. 在Spring中使用AspectJ来为domain object进行依赖注入 6.8.1.1. @Configurable object的单元测试 6.8.1.2. 多application context情况下的处理 6.8.2. Spring中其他的AspectJ切面 6.8.3. 使用Spring IoC来...

    J2EE开发全程实录

    在书中,正则表达式的章节介绍了这一强大的文本处理工具,包括为什么要使用正则表达式,以及如何在Java中使用`java.util.regex`包来编写和应用正则表达式。这对于处理字符串数据和进行数据验证至关重要。 程序优化...

    http请求绕过Filter的实现实例

    解决方案:让hessian请求绕过session过期filter。 filter配置中,不能加exclusion,所以需要用初始化参数给出不过滤的请求。本例中不过滤的格式为&gt;/SarService。 &lt;!--session过期filter --&gt; &lt;init-...

    Spring中文帮助文档

    6.8.1. 在Spring中使用AspectJ进行domain object的依赖注入 6.8.2. Spring中其他的AspectJ切面 6.8.3. 使用Spring IoC来配置AspectJ的切面 6.8.4. 在Spring应用中使用AspectJ加载时织入(LTW) 6.9. 更多资源 7...

    Spring+Hibernate+Xfire实现远程分布式调用

    在分布式系统中,它可以帮助我们处理数据持久化的问题,尤其是在多个服务之间需要共享数据时。通过Hibernate,我们可以定义实体类,映射到数据库表,然后使用查询语言(HQL)或Criteria API来执行CRUD操作。 Xfire...

    J2EE开发全程实录(JAVA项目开发)

    AOP是为了解决传统面向对象编程中横切关注点(如日志、事务管理)分散在各个类中的问题。AspectJ是Java社区广泛使用的AOP框架,而Spring AOP则是Spring框架的一部分,它提供了声明式AOP支持。在Spring AOP中,可以...

    dubbo基础使用 包含zk 1.8可用dubbo

    【标题】"dubbo基础使用 包含zk 1.8可用dubbo"涉及的核心技术是Dubbo和ZooKeeper,这两个组件在分布式系统中扮演着重要的角色。Dubbo是阿里巴巴开源的一款高性能、轻量级的Java服务治理框架,而ZooKeeper则是一个...

    Spring 2.0 开发参考手册

    6.8.1. 在Spring中使用AspectJ来为domain object进行依赖注入 6.8.2. Spring中其他的AspectJ切面 6.8.3. 使用Spring IoC来配置AspectJ的切面 6.8.4. 在Spring应用中使用AspectJ Load-time weaving(LTW) 6.9. ...

    Spring API

    6.8.1. 在Spring中使用AspectJ进行domain object的依赖注入 6.8.2. Spring中其他的AspectJ切面 6.8.3. 使用Spring IoC来配置AspectJ的切面 6.8.4. 在Spring应用中使用AspectJ加载时织入(LTW) 6.9. 更多资源 7...

    KK谈HTTP.doc

    - **Session ID**:通常通过设置`Set-Cookie`头来实现,将Session ID存储在客户端的Cookie中,这样每次客户端发起请求时都会携带这个Session ID。 - **URL重写**:另一种方法是在URL后面附加一个参数(如`;...

    spring chm文档

    6.8.1. 在Spring中使用AspectJ来为domain object进行依赖注入 6.8.2. Spring中其他的AspectJ切面 6.8.3. 使用Spring IoC来配置AspectJ的切面 6.8.4. 在Spring应用中使用AspectJ Load-time weaving(LTW) 6.9. ...

    springboot+dubbo分布式框架

    2. **分布式锁**:在多节点环境下解决并发问题,如Redis分布式锁、Zookeeper分布式锁等。 3. **分布式Session**:通过共享Session或者基于Token的无状态Session管理,实现跨服务的用户会话保持。 4. **读写分离**:...

    J2EE开发全程实录PDF J2EE开发全程实录PDF

    - **编写业务代码**:展示如何在Spring环境中使用AOP来增强业务逻辑。 - **装配pointcut和advice**:配置切入点和通知,将它们与目标类关联起来。 - **运行主程序**:演示如何启动应用程序并观察AOP的效果。 - **...

    1000道 互联网大厂Java工程师面试题(1)(1)(1).pdf

    7. **模糊查询 like 语句的写法**:使用 #{} 时,可以在 SQL 中使用 '%value%' 来实现模糊查询。 8. **Dao 接口的工作原理**:在 MyBatis 中,Dao 接口通常用于定义 SQL 操作的抽象方法,其背后使用动态代理机制来...

    JAVA技术架构及开发规范文档.docx

    Nginx的upstream配置用于实现服务器组内的负载均衡,通过ip_hash确保相同客户端IP始终访问同一服务器,解决session保持问题。 Web应用程序基于Spring框架开发,页面展示和控制包括动态同步请求、Ajax异步请求(可...

Global site tag (gtag.js) - Google Analytics