浏览 4827 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-01-26
最后修改:2011-01-26
最近在做一个项目,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封装,都是只做增量扩展。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2011-01-27
我前段时间也在寻找session的机制。
但是后来我没有采用这么复杂的操作,直接采用是head里面设置auth签名。把需要的用户名传到服务端。 |
|
返回顶楼 | |
发表时间:2011-02-03
zb7503 写道 我前段时间也在寻找session的机制。
但是后来我没有采用这么复杂的操作,直接采用是head里面设置auth签名。把需要的用户名传到服务端。 能不能详细的讲一下? |
|
返回顶楼 | |
发表时间:2011-02-25
zb7503 写道 我前段时间也在寻找session的机制。
但是后来我没有采用这么复杂的操作,直接采用是head里面设置auth签名。把需要的用户名传到服务端。 如果不使用集群中session集中管理的方案,是可以简单的将用户信息放到header里,我遇到的项目是在一个大型集群架构里,且需要使用MSM这样的中间件来集中管理session,所以不得已而实现session机制。 |
|
返回顶楼 | |