Using Sessions in Spring-MVC (including "scoped-proxies")
On the Spring-MVC video training course, I described three different approaches to handling sessions in Spring.
On the video, I mention that there is also a fourth way, but since the course was getting a bit long I said that I would cover this in a blog post, and here it is.
Thankyou to Bob Casazza for reminding me to do this.
First, a recap of the three approaches described on the video:
1: Use HttpSession directly.
With this approach, you declare HttpSession as a parameter to your controller method. The example on the course looks like this:
public
ModelAndView addToCart(
@RequestParam
(
"id"
)
int
id, HttpSession session)
{
ShoppingCart cart = (ShoppingCart)session.getAttribute(
"cart"
);
// etc, continue with the cart
}
Pros: it's simple, very much like you would do it in older Spring-MVC and other less capable frameworks.
Cons: it's messy, exposes your clean controller to the Servlet API and needs null checking after you've called getAttribute. Unit testing of your controller is now much harder to do (you need to Mock the HttpSession object).
I don't like this approach, I would avoid it unless necessary (later in the post, I'll explain when I would use it).
2: Scope the Controller
Make your controller session scoped. You can then simply instantiate the object you want to store in session scope as a member variable of the controller...
@Controller
@Scope
(
"session"
)
public
class
CartManagementController
{
private
ShoppingCart cart =
new
ShoppingCart();
@RequestMapping
(
"/addToCart"
)
public
ModelAndView addToCart(
@RequestParam
(
"id"
)
int
id)
{
// now just use the cart
}
}
Pros: A very clean controller, very unit testable.
Cons: A new controller is created for each session, the controller object must be stored in HttpSession. This could bloat the session and in particular could mean replication problems on a large scale system. (Replication: where your web application is hosted on multiple servers. Then the session has to be copied from one server to another. Whilst this is automatic, big sessions cause serious performance problems)
3: Scope the Objects in the Session
This is a narrowing of the session scope, and we session scope just the object we want to store in the session.
@Component
@Scope
(
"session"
)
public
class
ShoppingCart
{
// just a plain java class - member variables and methods as usual
}
|
Note that the class is now a Spring Bean.
Then, we inject instances of the class into the controller:
@Controller
@Scope
(
"request"
)
public
class
CartManagementController
{
@Autowired
private
ShoppingCart cart;
@RequestMapping
(
"/addToCart"
)
public
ModelAndView addToCart(
@RequestParam
(
"id"
)
int
id)
{
// now just use the cart
}
}
So, for each request, Spring creates an instance of the controller and then finds the shopping cart from the session.
Crucually, the controller in this approach MUST be request scoped. The default is for Spring to create a global singleton instance of the controller, and this would not work as a singleton is shared by all requests (you can't injection session scoped objects into singleton scoped objects anyway).
Pros: Clean testable controller as in approach two, with the added benefit of the session now only holds the relevant session data.
Cons: A new instance of the controller is created for each request. This is fine if the controller is "small", but if it is expensive to create (ie the constructor is slow for some reason), scalability would be a problem. Also, this approach is harder to understand because of the request scoped controller.
Ok, so they're the three approaches on the course. The problem is they all have drawbacks. I personally almost always use approach 3 where possible, but if I have a "heavy weight" controller, I'd consider using approach 1.
But the fourth approach removes all of the downsides of the previous. The only "con" of this approach is that it is much more complicated. It relies on Spring's best friend: proxies...
4: Use a <aop:scoped-proxy/>
This is covered in full in the Spring Reference manual (at the time of writing, at http://static.springsource.org/spring/docs/3.1.0.M1/spring-framework-reference/html/beans.html#beans-factory-scopes-other-injection)
The general idea of this approach is that you declare your session data as a regular spring bean, with a special tag applied to it (<scoped-proxy>). Your controller will remain a regaular Spring bean, as singleton scope.
With the scoped-proxy tag, your controller looks like it is holding a reference to the session data, but it is actually holding a reference to a proxy which Spring has generated at run time. This proxy's responsibility is to find a session each time it is accessed.
If this is a bit complicated, you might need to check out our AOP session in the Spring Fundamentals video. Or, you can just copy what's here:
Sadly, they haven't created an annotation for scoped-proxy, so your session data (the shopping cart) has to be declared in old-school XML. You add this to your Spring wiring (eg Dispatcher-servlet.xml on the course):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
xsi:schemaLocation="http://www.springframework.org/schema/beans
<!-- an HTTP Session-scoped bean exposed as a proxy -->
< bean id = "shoppingCart" class = "com.virtualpairprogrammers.ShoppingCart" scope = "session" >
<!-- this next element effects the proxying of the surrounding bean -->
< aop:scoped-proxy />
</ bean >
</ beans >
|
Now, your controller looks very simple:
1
2
3
4
5
6
7
8
9
10
11
12
|
@Controller public class CartManagementController
{ @Autowired
private ShoppingCart cart;
@RequestMapping ( "/addToCart" )
public ModelAndView addToCart( @RequestParam ( "id" ) int id)
{
// now just use the cart
}
} |
Pros: unit testable and clean as before, only session data is stored in the HttpSession, and the controller is a single-instance global singleton, so no issues with performance of creating them.
Cons: it's much harder to understand (I've taken hours over this post!) and you have to fall back to old fashioned XML wiring.
Conclusion:
The "fourth approach" is probably the most elegant in that it solves all of the technical problems identified earlier. But really, in most situations, approach 3 will be just fine. I have never felt the need to use this fourth approach, it seems like a really heavy solution to the session "problem".
In real life, I've always been happy to use approach 3, and when I'm worried about performance (in the rare case where I'm doing heavy work in the constructor), I'll use approach 1 instead.
I hope no-one minds me omitting approach four from the course, I felt that we had more than enough information on sessions - but I'm glad I've been able to cover it here.
相关推荐
Spring MVC 是一个基于Java的轻量级Web应用框架,它为开发者提供了模型-视图-控制器(MVC)架构,使开发人员能够更好地组织和分离应用程序的业务逻辑、数据处理和用户界面。Spring MVC是Spring框架的一个核心组件,...
Spring MVC 是一个强大的Java web开发框架,用于构建可维护、可扩展且结构良好的Web应用程序。这个框架基于Spring IoC(Inversion of Control)容器,它提供了Model-View-Controller(MVC)架构模式的实现,使得...
Spring MVC是Spring框架的一个模块,主要用于构建Web应用程序,而Spring JDBC则是Spring提供的用于简化数据库操作的工具。 【描述】"用spring4.0.5版本开发的,spring mvc,spring jdbc,最简单的用户登录,注册和...
### Spring MVC框架简介 Spring MVC 是一款基于 Java 的 Web 应用框架,它遵循 MVC(Model-View-Controller)设计模式。Spring MVC 提供了一种结构化的开发方式,旨在简化 Web 层的开发过程,同时提供了高度灵活性...
在本教程中,我们将深入探讨如何使用Spring MVC、Spring和Hibernate三大框架进行全注解的整合开发。这个视频教程系列的第12部分,将帮助开发者掌握如何在Java Web项目中高效地集成这三个核心框架,实现松耦合、可...
当我们遇到“Spring MVC No Session found for current thread”的错误时,这通常意味着在尝试访问HttpSession对象时,当前线程没有找到相关的session。这个问题可能是由于多种原因导致的,包括配置错误、过滤器设置...
《Spring MVC + Hibernate 实现BBS论坛系统详解》 在当今的互联网开发中,Spring MVC 和 Hibernate 是两个非常重要的框架,它们在企业级应用开发中起着关键作用。本项目"Spring MVC bbs"结合了Spring3和Hibernate,...
【Spring MVC + Hibernate + MySQL 整合详解】 在IT领域,Spring MVC、Hibernate和MySQL是构建Web应用程序的常用技术栈。Spring MVC作为Spring框架的一部分,提供了强大的MVC(Model-View-Controller)架构,用于...
Spring MVC 是一个强大的Java web开发框架,用于构建可维护、高性能和灵活的Web应用程序。这个"spring mvc login demo"项目旨在提供一个基础的登录功能示例,帮助开发者理解如何在Spring MVC环境中实现用户身份验证...
可用于分析spring mvc源码、spring mvc父子容器初始化流程、session和cookie机制、spring session等,也可以用于学习Java Web(servlet、filter、listener等)、spring源码等。 该项目使用servlet3.0规范,无web.xml...
本教程专注于使用Spring、Spring MVC和MyBatis这三个关键组件进行实战教学。这三者构成了Java EE开发中的重要支柱,为开发者提供了强大的功能和灵活性。 Spring框架是Java EE开发的核心,它是一个全功能的容器,...
这是一个基于Java技术栈的通用后台管理系统,主要使用了Spring MVC、Spring、Hibernate、Bootstrap和Maven等技术。这些技术在IT行业中广泛应用于企业级Web应用开发,构建高效、可维护的系统。下面将分别详细解释这些...
Spring mvc 分步式session的实例详解 Session代表服务器与浏览器的一次会话过程,它的信息是保存在服务器端的。在Servlet中,session指的是HttpSession类的对象。服务器在创建session后,会把sessionid以cookie的...
在Spring项目中,通常会使用`LocalSessionFactoryBean`配置Hibernate,并通过`SessionFactory`实例来创建`Session`。而使用Spring Data JPA时,只需要配置数据源、JPA供应商(如Hibernate)以及实体扫描路径即可。...
在Spring MVC框架中,`Locale`是用来处理应用程序中的多语言支持的关键组件。它定义了用户的语言和地区设置,例如中文(zh_CN)或英文(en_US)。这篇博客文章将深入探讨如何在Spring MVC应用中实现语言切换功能,以...
Servlet、JSP和Spring MVC是Java Web开发中的三个重要技术,它们在构建动态网页和企业级应用程序中扮演着核心角色。下面将详细解释这三个技术及其相互关系。 **Servlet** 是Java编程语言中的一种接口,由Java ...
Spring MVC、Spring 和 Hibernate 是 Java 开发中三个非常重要的框架,它们共同构成了企业级应用的基石,尤其是在构建大型、复杂的Web应用程序时。Spring MVC 作为Spring框架的一部分,负责处理HTTP请求,提供MVC...
在本项目中,我们探讨的是一个基于Spring MVC框架构建的JavaWeb应用。Spring MVC是Spring框架的一个模块,专为创建Web应用程序提供模型-视图-控制器(MVC)架构支持。这个项目涉及到的功能包括分页显示、单个或批量...
Spring-session-data-redis允许我们在Spring MVC应用中利用Redis存储和恢复HTTP会话,而Spring-data-redis则提供了操作Redis数据库的一系列高级API。 首先,我们来看Spring Session。Spring Session的主要目标是...
Spring MVC 是一个基于 Java 的轻量级 Web 开发框架,它是 Spring 框架的一部分,专为构建可维护、高性能的 Web 应用程序而设计。这个“spring mvc项目后端源码”包含了实现此类应用程序的核心组件和配置。下面我们...