`
lvff1314
  • 浏览: 11979 次
  • 性别: 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...

    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的效果。 - **...

    最热门的Java 分布式面试题汇总

    4. 分布式session一致性:可以通过Session复制、Session黏贴或使用分布式session存储(如Redis、Memcached)来保持一致性。 5. ZooKeeper的ZAB协议:Zookeeper原子广播协议,用于保证分布式环境中数据的一致性,...

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

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

Global site tag (gtag.js) - Google Analytics