- 浏览: 570195 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
西蜀石兰:
为什么会调两次uniqueResult(),是不是写错了,亲
Hibernate使用count(*)取得表中记录总数 -
gaoyaohuachina:
金全 怎么装探针啊
OC4J的使用 -
fs08ab:
itstarting 写道jacktea 写道mvc 的只扫描 ...
解决 spring mvc 3.0 结合 hibernate3.2 使用<tx:annotation-driven>声明式事务无法提交的问题 -
fs08ab:
大神和博主好,我有一事不明,两位在问题分析中的描述,我理解为是 ...
解决 spring mvc 3.0 结合 hibernate3.2 使用<tx:annotation-driven>声明式事务无法提交的问题 -
帅气的强哥:
...
context:component-scan配置策略
本文部分内容参考至:http://anffvf.blog.163.com/blog/static/314754201101342148699/
WEB 应用通常会引入 Session,用来在服务端和客户端之间保存一系列动作/消息的状态,比如网上购物维护 user 登录信息直到 user 退出。在
user 登录后,Session 周期里有很多 action 都需要从 Session 中得到
user,再验证身份权限,或者进行其他的操作。这其中就会涉及到程序去访问 Session属性的问题。在java中,Servlet 规范提供了
HttpSession对象来满足这种需求。开发人员可以从 HttpServletRquest对象得到
HttpSession,再从HttpSession中得到状态信息。
还是回到购物车的例子,假设在 controller
某个方法(本文简称为action)中我们要从HttpSession中取到user对象。如果基于Servlet,标准的代码会是这样的:
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { User user = (User)req.getSession().getAttribute("currentUser"); // }
这样的代码在传统的Servlet程序中是很常见的:因为使用了
Servlet API,从而对 Servlet API产生依赖。这样如果我们要测试 action,我们就必须针对
HttpServletRequest、HttpServletResponse 和 HttpSession类提供 mock 或者 stub
实现。当然现在已经有很多开源的 Servlet 测试框架帮助我们减轻这个痛苦,包括 Spring 就自带了对了这些类的 stub
实现,但那还是太冗繁琐碎了。那有没有比较好的办法来让我们的 controller 更 POJO,让我们的 action 脱离 Servlet API
依赖,更有益于测试和复用呢?我们来看看在 Spring2.5 中访问 Session
属性的几种策略,并将在本博的后续文章继续探究解决方案选择后面的深层含义。
(一)通过方法参数传入HttpServletRequest对象或者HttpSession对象
Spring对annotationed的
action 的参数提供自动绑定支持的参数类型包括 Servlet API 里面的
Request/Response/HttpSession(包含Request、Response在Servlet API
中声明的具体子类)。于是开发人员可以通过在 action 参数中声明 Request 对象或者 HttpSession
对象,来让容器注入相应的对象。
action 的代码如下:
@RequestMapping public void hello(HttpSession session){ User user = (User)session.getAttribute("currentUser"); // }
优点:
1. 程序中直接得到底层的
Request/HttpSession 对象,直接使用 Servlet API 规范中定义的方法操作这些对象中的属性,直接而简单。
2. action
需要访问哪些具体的 Session 属性,是由自己控制的,真正精确到 Session 中的每个特定属性。
不足:
1. 程序对 Servlet
API 产生依赖。虽然 controller 类已经不需要从 HttpServlet 继承,但仍需要 Servlet API
才能完成编译运行,乃至测试。
2. 暴露了底层 Servlet API,暴露了很多并不需要的底层方法和类,开发人员容易滥用这些
API。
(二)通过定制拦截器(Interceptor)在controller类级别注入需要的User对象
Interceptor 是
Spring 提供的扩展点之一,SpringMVC 会在 handle 某个 request 前后调用在配置中定义的 Interceptor
完成一些切面的工作,比如验证用户权限、处理分发等,类似于 AOP。那么,我们可以提取这样一个“横切点”,在 SpringMVC 调用 action 前,在
Interceptor 的 preHandle 方法中给 controller 注入 User 成员变量,使之具有当前登录的 User
对象。
此外还需要给这些特定 controller 声明一类 interface,比如 IUserAware。这样开发人员就可以只针对这些需要注入
User 对象的 controller 进行注入增强。
IUserAware 的代码:
public interface IUserAware { public void setUser(); }
controller
的代码:
@Controller public GreetingController implements IUserAware { private User user; public void setUser(User user){ this.user = user; } @RequestMapping public void hello(){ //user.sayHello(); } // }
Interceptor 的代码:
public class UserInjectInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) throws Exception { if (handler.isAssignableFrom(IUserAware)){ User user = (User)httpServletRequest.getSession().getAttribute("currentUser"); IUserAware userAware = (IUserAware) handler; userAware.setUser(user); } return super.preHandle(httpServletRequest, httpServletResponse, handler); } // }
为了让 SpringMVC 能调用我们定义的 Interceptor,我们还需要在 SpringMVC 配置文件中声明该
Interceptor,比如:
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"> <property name="interceptors"> <list> <ref bean="userInjectInterceptor"/><!-- userInjectInterceptor bean 的声明省略--> </list> </property> </bean>
优点:
1. 对 Servlet API 的访问被移到了自 SpringMVC
API 扩展的 Interceptor,controller 不需要关心 User 如何得到。
2. 开发人员可以通过随时添加或移除
Interceptor 来完成对不同参数在某一类型 controller 上的注入。
3. controller 的 User
对象通过外界注入,测试时开发人员可以很容易地注入自己想要的 User 对象。
4. controller 类去掉了对 Servlet API 的依赖,更
POJO 和通用。
5. controller 类是通过对 interface 的声明来辅助完成注入的,并不存在任何继承依赖。
不足:
1.
SpringMVC 对 controller 默认是按照单例(singleton)处理的,在 controller
类中添加一个成员变量,可能会引起多线程的安全问题。
2. 因为 User 对象是定义为 controller 的成员变量,而且是通过 setter
注入进来,在测试时需要很小心地保证对controller 注入了 User 对象,否则有可能我们拿到的就不一定是一个“好公民”(Good
Citizen)。
其实,一言而蔽之,这些不足之所以出现,是因为我们把某个 action 级别需要的 User 对象上提到 controller
级别,破坏了 the convention of stateless for controller classes,而 setter
方式的注入又带来了一些隐含的繁琐和不足。当然,我们可以通过把 controller 声明为“prototype”来绕过 stateless
的约定,也可以保证每次 new 一个 controller 的同时给其注入一个 User 对象。但是我们有没有更简单更 OO
的方式来实现呢?答案是有的。
(三)通过方法参数处理类(MethodArgumentResolver)在方法级别注入User对象
正如前面所看到的,SpringMVC
提供了不少扩展点给开发人员扩展,让开发人员可以按需索取,plugin 上自定义的类或 handler。那么,在 controller
类的层次上,SpringMVC 提供了 Interceptor 扩展,在 action 上有没有提供相应的 handler 呢?如果我们能够对 action
实现注入,出现的种种不足了。
通过查阅 SpringMVC API 文档,SpringMVC 其实也为 action 级别提供了方法参数注入的
Resolver 扩展,允许开发人员给 HandlerMapper 类 set 自定义的
MethodArgumentResolver。
action 的代码如下:
@RequestMapping public void hello(User user){ //user.sayHello() }
Resolver
的代码如下:
public class UserArgumentResolver implements WebArgumentResolver { public Object resolveArgument(MethodParameter methodParameter, NativeWebRequest webRequest) throws Exception { if (methodParameter.getParameterType().equals(User.class)) { return webRequest.getAttribute("currentUser", RequestAttributes.SCOPE_SESSION); } return UNRESOLVED; } }
配置文件的相关配置如下:
<bean class="org.springframework.web.servlet.mvc.annotation.OwnAnnotationMethodHandlerAdapter"> <property name="customArgumentResolver"> <ref bean="userArgumentResolver"/><!-- userArgumentResolver bean 的定义省略 --> </property> </bean>
优点:
1. 具备第二种方案的所有优点
2.
真正做到了按需分配,只在真正需要对象的位置注入具体的对象,减少其他地方对该对象的依赖。
3. 其他人能很容易地从 action 的参数列表得知
action 所需要的依赖,API 更清晰易懂。
4. 对于很多 action
需要的某一类参数,可以在唯一的设置点用很方便一致的方式进行注入。
不足:
1. 对象依赖注入是针对所有 action,
注入粒度还是较粗。不能做到具体 action 访问具体的 Session 属性
(四)通过 SpringMVC 的 SessionAttributes Annotation 关联 User 属性
SpringMVC 文档提到了 @SessionAttributes
annotation,和 @ModelAttribute 配合使用可以往 Session 中存或者从 Session
中取指定属性名的具体对象。文档里说;
The type-level @SessionAttributes annotation declares
session attributes used by a specific handler. This will typically list the
names of model attributes which should be transparently stored in the session or
some conversational storage, serving as form-backing beans between subsequent
requests.
很明显,@SessionAttributes 是用来在 controller 内部共享 model
属性的。从文档自带的例子来看,标注成 @SessionAttributes 属性的对象,会一直保留在 Session 或者其他会话存储中,直到
SessionStatus 被显式 setComplete()。那这个 annotation 对我们有什么帮助呢?
答案就是我们可以在需要访问
Session 属性的 controller 上加上 @SessionAttributes,然后在 action 需要的 User 参数上加上
@ModelAttribute,并保证两者的属性名称一致。SpringMVC 就会自动将 @SessionAttributes 定义的属性注入到
ModelMap 对象,在 setup action 的参数列表时,去 ModelMap 中取到这样的对象,再添加到参数列表。只要我们不去调用
SessionStatus 的 setComplete() 方法,这个对象就会一直保留在 Session 中,从而实现 Session
信息的共享。
controller的代码如下:
@Controller @SessionAttributes("currentUser") public class GreetingController{ @RequestMapping public void hello(@ModelAttribute("currentUser") User user){ //user.sayHello() } // }
使用这种方案,还需要在 SpringMVC 配置文件的
ViewResolver 定义处,加上 p:allowSessionOverride="true",这样如果你对 User 对象做了修改,SpringMVC
就会在渲染 View 的同时覆写 Session 中的相关属性。
优点:
1. 具备第二种方案的所有优点
2. 使用
Annotation 声明对 Session 特定属性的存取,每个 action 只需要声明自己想要的 Session 属性。
3. 其他人能很容易地从
action 的参数列表得知 action 所需要的依赖,API 更清晰易懂。
不足:
1. 对于相同属性的 Session 对象,需要在每个
action 上定义。
2. 这种方案并不是 SpringMVC 的初衷,因此有可能会引起一些争议。
纵观这四类方法,我们可以看出我们对
Session 属性的访问控制设置,是从所有 Servlet,到某一类型的 controller 的成员变量,到所有 action 的某一类型参数,再到具体
action 的具体对象。每种方案都有各自的优点和不足:第一种方案虽然精确,但可惜引入了对 Servlet API 的依赖,不利于 controller
的测试和逻辑复用。第二、三种方案虽然解决了对 Servlet API 的依赖,也分别在 controller 和 action 级别上提供了对 Session
属性的访问,但注入粒度在一定程度上还是不够细,要想对具体属性进行访问可能会比较繁琐。不过,这在另一方面也提供了简便而统一的方法来对一系列相同类型的参数进行注入。第四种方案通过使用
Annotation,不仅摆脱了 Servlet API 的依赖,而且在 action 级别上提供了对 Session
具体属性的访问控制。但是这种访问有可能会粒度过细,需要在很多不同 action 上声明相同的 annotation。而且,毕竟这种用法并不是 SpringMVC
的初衷和推荐的,可能会带来一些争议。
本文演示了 Spring2.5 访问 Session
属性的几种不同解决方案,并分析了各自的优点和不足。本文并不打算对这些解决方案评出对错,只是试图列出在选择方案时的思维过程以及选择标准。每种方案都能满足某一类上下文的需求,在特定的开发环境和团队中都可能会是最优的选择。但是笔者还是发现,整个过程中,一些平常容易忽视的
OOP 的准则或者原则在发挥着效应,鉴于本文篇幅已经较长,就留到后续文章中继续探讨解决方案选择背后的深层含义,敬请期待。
评论
1. 程序对 Servlet API 产生依赖。虽然 controller 类已经不需要从 HttpServlet 继承,但仍需要 Servlet API 才能完成编译运行,乃至测试。
2. 暴露了底层 Servlet API,暴露了很多并不需要的底层方法和类,开发人员容易滥用这些 API。
对于这俩点:
1.你只有是在web容器里面运行的项目,我请问你 你怎么脱离Servlet API ?你给我开发一段脱离Servlet API 的处理请求的代码段?只要在容器中运行,用Servlet API 有什么不好?产生依赖?就好比吃饭,你可以自己用筷子夹菜,但是你不想自己夹,就想等别人喂,一旦喂你的那个人,出现异常情况,你怎么办?
2.“暴露了 底层 Servlet API”,这个只能说明 实际的开发人员的问题
发表评论
-
解决m2clipse无法下载依赖的问题
2013-02-25 11:41 0有时候会出现在nexus中可以搜索到jar,可是eclips ... -
XML-RPC XmlRpcClientException: Failed to parse server's response if isEnabledFor
2012-03-15 12:12 0org.apache.xmlrpc.client.XmlRpc ... -
解决Hudson 插件列表中deploy plugin 无法deploy到tomcat7.*的问题
2011-12-29 20:52 2022Hudson 2.2 插件列表中deploy plugin为1 ... -
解决Hudson 插件列表中deploy plugin 无法deploy到tomcat7.*的问题
2011-12-29 20:52 2Hudson 2.2 插件列表中deploy plugin为1 ... -
org.hibernate.TransientObjectException: object references an unsaved transient i
2011-10-15 21:10 9043异常1:not-null property referen ... -
部署自己的构建至私服nuxus
2011-07-06 15:51 19301、配置部署Maven 2、部署nexus(参考Nexus官 ... -
java中两个整数相除得到小数点并保留两位小数的方法
2010-10-29 17:43 5506当两个整数相除时,由于小数点以后的数字会被截断,使运算结果为整 ... -
Comparator
2010-09-14 16:25 1387import java.util.Comparator; ... -
解决 spring mvc 3.0 结合 hibernate3.2 使用<tx:annotation-driven>声明式事务无法提交的问题
2010-07-16 18:32 122621、问题复现 spring 3.0 + hiber ... -
深入浅出REST
2010-07-06 16:04 1186转载自http://www.infoq.com/cn/arti ... -
context:component-scan配置策略
2010-06-23 10:44 23106Spring applicationContext.xml的& ... -
Spring framework实现定时器之Quartz
2009-07-27 13:54 1428转载自:飞扬部落编程仓库 : http://www.busfl ... -
java常用的日期工具类
2009-07-24 15:32 4643package com.fengzhiyin.util; ... -
SSH项目中利用struts的ExceptionHandler处理异常
2009-07-24 11:54 3615一、概述 在Struts1.X的版本中加入了对 ... -
Java 中 Vector、ArrayList、List 使用深入剖析
2009-05-12 11:18 1463线性表,链表,哈希表是常用的数据结构,在进行Java开发时,J ... -
Java 处理% 、格式化数字
2009-05-12 10:42 2120这个是我在程序使用的 ... -
double处理
2009-04-17 15:59 1288import java.text.DecimalFormat; ... -
Java栈与堆
2009-02-03 15:11 991Java栈与堆 ----对这两个 ... -
jstl中的varStatus
2008-12-25 09:57 1419jstl中的varStatus 和 var 属性一样, var ... -
硬回车、软回车、java转义字符
2008-07-19 12:24 4318软回车(Soft Return):软回车是在字处理程序中作为自 ...
相关推荐
7.1. Alternate Spring MVC configuration 7.1.1. Customizing DispatcherServlet configuration 7.1.2. Adding additional servlets and filters 7.1.3. Declaring DispatcherServlet in web.xml 7.2. Processing ...
弃用了struts,用spring mvc框架做了几个项目,感觉都不错,而且使用了注解方式,可以省掉一大堆配置文件。本文主要介绍使用注解方式配置的spring mvc,之前写的spring3.0 mvc和rest小例子没有介绍到数据层的内容,...
.3. 任务规划 2.6.4. 对Java 5(Tiger)的支持 2.7. 移植到Spring 2.0 2.7.1. 一些变化 2.7.1.1. Jar包 2.7.1.2. XML配置 2.7.1.3. Deprecated的类和方法 2.7.1.4. Apache OJB 2.7.1.5. iBatis 2.8. 更新的样例应用...
build.gradle 中指定): org.springframework.boot :用于基础 MVC 框架org.springframework.security :用于各种与安全相关的目的,包括身份验证和散列org.springframework.session :用于用户会话org.hibernate :...
7.10.3. 原型目标源 7.10.4. ThreadLocal目标源 7.11. 定义新的Advice类型 7.12. 更多资源 8. 测试 8.1. 简介 8.2. 单元测试 8.2.1. Mock对象 8.2.2. 单元测试支持类 8.3. 集成测试 8.3.1. 概览 8.3.2. ...
在Spring环境中使用YAML暴露属性 iii. 23.6.3. Multi-profile YAML文档 iv. 23.6.4. YAML缺点 vii. 23.7. 类型安全的配置属性 i. 23.7.1. 第三方配置 ii. 23.7.2. 松散的绑定(Relaxed binding) iii. 23.7.3. @...
3. New Features and Enhancements in Spring Framework 4.0 ............................................ 17 3.1. Improved Getting Started Experience .........................................................
7.10.3. 原型目标源 7.10.4. ThreadLocal目标源 7.11. 定义新的Advice类型 7.12. 更多资源 8. 测试 8.1. 简介 8.2. 单元测试 8.2.1. Mock对象 8.2.2. 单元测试支持类 8.3. 集成测试 8.3.1. 概览 8.3.2. ...
7.10.3. 原型目标源 7.10.4. ThreadLocal目标源 7.11. 定义新的通知类型 7.12. 更多资源 8. 测试 8.1. 简介 8.2. 单元测试 8.3. 集成测试 8.3.1. Context管理和缓存 8.3.2. 测试fixture的依赖注入 8.3.3. ...
7.10.3. 原型目标源 7.10.4. ThreadLocal目标源 7.11. 定义新的通知类型 7.12. 更多资源 8. 测试 8.1. 简介 8.2. 单元测试 8.3. 集成测试 8.3.1. Context管理和缓存 8.3.2. 测试fixture的依赖注入 8.3.3. ...
Spring mvc 分步式session的实例详解 Session代表服务器与浏览器的一...下面以spring MVC以例来说明如果创建分步式session. 1、login – 登录页 login表示用户跳转到登录页面,这个时候可以生成唯一key为sessionid的ses
24.6.3. Multi-profile YAML Documents 24.6.4. YAML Shortcomings 24.7. Type-safe Configuration Properties 24.7.1. Third-party Configuration 24.7.2. Relaxed Binding 24.7.3. Merging Complex Types 24.7.4. ...
3. New Features and Enhancements in Spring Framework 4.0 ............................................ 17 3.1. Improved Getting Started Experience .........................................................
可用于分析spring mvc源码、spring mvc父子容器初始化流程、session和cookie机制、spring session等,也可以用于学习Java Web(servlet、filter、listener等)、spring源码等。 该项目使用servlet3.0规范,无web.xml...
• Spring MVC 以上框架都是非常优秀的。说实话,如果阿里巴巴网站在2001年开始,就有这么多可选择的话,无论选择哪一个都不会有问题。因为这些年来,所有的开源Web框架都在互相学习、并趋于相似。Webx也不例外,...
spring-mvc-redis-session Spring-mvc session with redis. 使用redis作为session的持久化媒介。 特别说明 注意修改RedisHttpSession中的参数: COOKIE=session id DOMAIN=域名
参考资料: http://docs.spring.io/spring-session/docs/current-SNAPSHOT/reference/html5/guides/security.html http://blog.csdn.net/xiejx618/article/details/43059683
主要介绍了详解Spring MVC拦截器实现session控制,使用session监听,重复登录后,强制之前登录的session过期。有兴趣的可以了解一下。
32.3.3使用CAS认证无状态服务 249 配置CAS以获取代理授予票证 249 使用代理票证调用无状态服务 250 32.3.4代理票证认证 251 33. X.509认证 253 33.1概述 253 33.2将X.509身份验证添加到您的Web应用程序 253 33.3在...