1.问题
众所周知,标准的Servlet API中,有一个HttpSession的接口。本来HTTP协议是无状态的,通过session机制,就能把无状态的变成有状态的。有了session的支持,WEB应该就能够跟踪一个用户的操作状态。在一个WEB应用中,你可以这样使用session:
// 取得session对象
HttpSession session = request.getSession();
// 在session中保存用户状态
session.setAttribute(“loginId”, “myName”);
// 在另一个请求中,取出session的状态
String myName = (String) session.getAttribute(“loginId”);
如何保存session中的状态?一般的做法,是将session对象保存在内存里,然后用一Session ID来索引。同一时间,会有很多session被保存在服务器的内存里,但每个session的ID都是不一样的。对于Java Servlet,常见的做法是把这个Session ID保存在cookie里。这样一来,凡是cookie值相同的所有的请求,就被看作是在同一个session中的请求。由于内存是有限的,较先进的服务器会把session对象交换到文件中,以确保内存中的session数保持在一个合理的范围内。
为了提高系统扩展性和可用性,我们会使用集群技术 —— 就是一组独立的机器共同运行同一个应用。对用户来讲,集群相当于一台服务器。而实际上,同一用户的两次请求可能被分配到两台不同的服务器上来处理。这样一来,怎样保证两次请求中存取的session值一致呢?
多数的服务器会使用session复制的方法:当session的值被改变时,将它复制到其它机器上。这个方案又有两种具体的实现,一种是广播的方式。这种方式下,任何一台服务器都保存着所有服务器所接受到的session对象。服务器之间随时保持着同步,因而所有服务器都是等同的。可想而知,当访问量增大的时候,这种方式花费在广播session上的带宽有多大,而且随着机器增加,网络负担成指数级上升,不具备高度可扩展性。另一种是TCP-ring的方式,也就是把集群中所有的服务器看成一个环,A->B->C->D->A,首尾相接。把A的session复制到B,B的session复制到C,……,以此类推,最后一台服务器的session复制到A。这样,万一A宕机,还有B可以顶上来,用户的session数据不会轻易丢失。但这种方案也有缺点:一是配置复杂;二是每增添/减少一台机器时,ring都需要重新调整,这将成为性能瓶颈;三是要求前端的Load Balancer具有相当强的智能,才能将用户请求分发到正确的机器上。
另一种保存session的思路是,将session保存在单一的数据源中。这个数据源可被集群中所有的机器所共享。这样一来,复制就不是问题了。然而性能成了问题。每个用户请求,都需要访问后端的数据源(很可能是数据库)来存取用户的数据。这种思路的第二个问题是:缺少应用服务厂商的支持 —— 很少有应用服务器支持这种方案,更不用说数据源有很多种(MySQL、Oracle、Hsqldb等各种数据库、专用的session server等)了。第三个问题是:数据源成了系统的瓶颈,一但这个数据源崩溃,所有的应用都不可能正常运行了。
综上所述,session看起来很简单,实际上是一个大问题!犹其是对一个访问量极高的大型网站而言。
2.解决方案
2.1.将session数据保存在客户端
前面所说的通过复制,或者通过单一数据源,都可以解决集群中分布式session的问题,然而存在前面所说的很多问题。另一种思路,是把session保存在客户端。这样一来,服务器就变成无状态了,就能够做到线性可扩展和极高的可用性。怎么保存呢?目前唯一的方法,恐怕就是cookie了。
Cookie方案也不是完美的,有以下限制:
1. Cookie数量和长度的限制。每个domain最多只能有20条cookie,每个cookie长度不能超过4KB,否则会被截掉。
2. 安全性问题。如果cookie被人拦截了,那人就可以取得所有的session信息。即使加密也与事无补,因为拦截者并不需要知道cookie的意义,他只要原样转发cookie就可以达到目的了。
3. 有些状态不可能保存在客户端。例如,为了防止重复提交表单,我们需要在服务器端保存一个计数器。如果我们把这个计数器保存在客户端,那么它起不到任何作用。
虽然有上述缺点,但是对于其优点(极高的扩展性和可用性)来说,就显得微不足道。然而我们仍然要设法回避上述的缺点,方法是:
1. 通过良好的编程,控制保存在cookie中的session对象的大小。
2. 通过加密和安全传输技术(SSL),减少cookie被破解的可能性。
3. 只在cookie中存放不敏感数据,即使被盗也不会有重大损失。
4. 控制cookie的生命期,使之不会永远有效。偷盗者很可能拿到一个过期的cookie。
2.2.将session保存在专用的服务器上
前面提到,由于cookie机制本身的限制,我们不可能将所有的数据都放在cookie中,势必要有服务器端的方案来辅助。相比复制的方法,单一的数据源更简单更可靠。我们可以使用数据库来保存这部分session。然而我倾向于使用更廉价、更轻量的存储。事实证明,BerkeleyDB是一种很好的选择。
由于我们只把少量关键的信息保存在服务端,因而这个数据源的压力不会非常大。事实证明,BerkeleyDB在保持良好的可用性的前提下,具有相当高的系统容量,可以高效处理大量的数据请求。
2.3.创建通用的session框架
不是Java Servlet API的session机制不够灵活,而是多数应用服务器并没有留出足够的余地,来让你自定义session的存储方案。根据上面的讨论,任何一种session方案都有其优缺点。最好的方法是把它们结合起来。例如:结合cookie-based session和berkeleyDB-based session,就可以解决我们的绝大部分问题。
纵使某个应用服务器提供了对外扩展的接口,可以自定义session的方案,我们也不大可能使用它。为什么呢?因为我们希望保留选择应用服务器软件的自由。
因此,最好的方案,不是在应用服务器上增加什么新功能,而是在WEB应用框架上做手术。一但我们在WEB应用框架中实现了这种灵活的session框架,那么我们的应用可以跑在任何标准的JavaEE应用服务器上。
除此之外,一个好的session框架还应该做到对应用程序透明。具体表现在:
1. 使用标准的HttpSession接口,而不是增加新的API。这样任何WEB应用,都可以轻易在两种不同的session机制之间切换。
2. 应用程序不需要知道session中的对象是被保存到了cookie中还是别的什么地方。
3. Session框架可以把同一个session中的不同的对象分别保存到不同的地方去,应用程序同样不需要关心这些。例如,把一般信息放到cookie中,关键信息放到berkeleyDB中。甚至同是cookie,也有持久和临时之分,有生命期长短之分。
分享到:
相关推荐
在Spring框架中,WebSocket是一种用于实现双向通信的技术,它可以提供实时、低延迟的数据传输,而HttpSession则是HTTP协议中用于跟踪用户会话的一种机制。在Spring 4版本中,我们经常需要结合WebSocket与HttpSession...
在实际应用中,通常会配合Ajax或者Web框架(如Spring MVC)的视图解析来实现。 5. **用户输入验证**:用户在看到验证码图片后输入验证码,然后将输入的验证码与服务器端存储的验证码进行比对。如果匹配,登录过程...
5. **会话管理**:通过HttpSession对象,读者可以学习如何在用户会话间存储和共享数据。 6. **模板引擎**:用于生成动态HTML的工具,如FreeMarker或JSP,可以减少视图层的复杂性。 7. **异常处理**:理解如何使用...
### Java面试题之三大框架题目详解 #### 一、为何实体类需实现序列化接口? 在探讨这个问题前,我们先了解下序列化的概念及其应用场景。序列化是指将对象的状态信息转换为可以存储或传输的形式的过程。在Java中,...
5. **使用请求参数和会话**:在Servlet中,我们可以通过HttpServletRequest对象获取请求参数,通过HttpSession对象处理会话数据,这些在Struts框架中也是类似的。 在实际项目中,Struts框架提供了更高级的功能,如...
此外,Shiro还支持通过调用`HttpServletRequest`或`HttpSession`的方法来操作会话,而这些调用最终会被代理给内部的原生会话API。 ### 结论 Spring Shiro安全框架不仅具备强大的功能,而且在易用性和灵活性方面表现...
4. **会话管理**:学习如何使用HttpSession对象保持用户状态,以及何时使用cookie来辅助会话管理。 5. **路径映射与URL路由**:设计一个优雅的URL路由系统,将HTTP请求映射到对应的处理逻辑,如使用注解或配置文件...
验证成功后,可以将用户信息保存在HttpSession中,实现会话跟踪。此外,Spring的安全模块Spring Security可以用来实现更复杂的权限控制和认证。 总的来说,Spring MVC、Spring和Hibernate的组合提供了一套完整的...
在Java EE开发中,JAR包通常包含了库、框架或者特定功能的实现。"servletapi.jar"就是这样一个专门针对Servlet API的JAR文件,它包含了Servlet规范定义的类和接口,如Servlet、Filter、Listener等,使得开发者能够...
这可能涉及到使用HttpSession对象,或者自定义会话存储和管理机制。 5. **拦截器与过滤器**: 拦截器和过滤器可以对请求和响应进行预处理和后处理。拦截器通常用于AOP(面向切面编程),如权限检查、日志记录等;...
- 直接在方法参数中声明`HttpServletRequest request`或`HttpSession session`,SpringMvc会自动注入。 9. **@RequestMapping注解**: - 用在类上,表示类的所有处理方法都以该注解的URL作为前缀。 10. **...
通过消除繁琐的“衔接”代码,如解析查询参数、管理HttpSession等,Tapestry帮助开发者专注于业务逻辑,从而降低了代码量,提升了开发效率。 3. **一致性与可复用性**: Tapestry提供了统一的方式来构建Web应用...
在IT行业中,构建网站框架是开发Web应用的关键步骤。MyEclipse是一款强大的集成开发环境(IDE),特别适合Java EE项目的开发,包括JSP(JavaServer Pages)等技术。本篇文章将详细探讨如何在MyEclipse下搭建一个具备...
在Java Web中,可以使用HttpSession接口来创建、存储和管理session数据。 至于自定义MVC框架,开发者通常会基于现有的框架技术,如Spring MVC,进行二次开发。主流的框架如Struts、Spring、Hibernate等提供了丰富的...
6. **会话管理**: 需要手动管理用户的会话状态,可以使用`HttpSession`对象来存储用户状态信息,如登录状态、购物车等。 7. **错误处理与异常捕获**: 编写异常处理代码以确保系统能够优雅地处理错误和异常,同时...
8. **访问Web元素**:通过实现`SessionAware`接口,Struts2能够注入HttpSession到Action中的Map类型变量,从而方便访问Session数据。 9. **Value Stack**:Value Stack中的值存储在request作用域中,Action中的变量...
这通常通过HttpSession接口实现,允许在服务器端存储用户信息,跨多个请求保持状态。 5. **模板引擎**:为了生成动态HTML,框架可能集成如FreeMarker或Thymeleaf这样的模板引擎,将数据模型与HTML模板结合,生成...
此外,HttpSession和ServletContext对象分别用于存储session和application级别的共享数据。 1.2 JSP组件 JSP是一种结合了HTML和Java的页面,它的执行过程涉及到JSP容器将JSP转换为Servlet源码,再编译为Servlet类。...