public class MyInterceptor implements HandlerInterceptor {
private static final Logger log = LoggerFactory.getLogger(MyInterceptor.class);
private static final String MY_APPLICATION_CONTEXT = "MYAPPLICATIONCONTEXT";
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
IContextAware controllerAware = null;
HandlerMethod handlerMethod = (HandlerMethod) handler;
Class<?> clazz = handlerMethod.getBeanType();
Type[] interfaces = clazz.getGenericInterfaces();
if (interfaces != null && interfaces.length > 0) {
for (int i = 0; i < interfaces.length; i++) {
if (interfaces[i] == IContextAware.class) {
controllerAware = (IContextAware) handlerMethod.getBean();
}
}
}
HttpSession session = request.getSession();
if (session == null) {
session = request.getSession(true);
}
log.info("当前HttpSession的sessionId={}", session.getId());
MyApplicationContext context = (MyApplicationContext) session.getAttribute(MY_APPLICATION_CONTEXT);
if (context == null) {
context = new MyApplicationContextImpl();
session.setAttribute(MY_APPLICATION_CONTEXT, context);
}
log.info("当前自定义上下文对象hashcode={}", context.hashCode());
controllerAware.setContext(context);
return true;
}
……
}
为了让 SpringMVC 能调用我们定义的 Interceptor,我们还需要在 SpringMVC 配置文件中声明该 Interceptor
<bean>
<property>
<list>
<ref bean="myContextInterceptor"/>
</list>
</property>
</bean>
<bean></bean>
优点:
1. 对 Servlet API 的访问被移到了自 SpringMVC API 扩展的 Interceptor,controller 不需要关心自定义上下文对象如何得到。
2. 开发人员可以通过随时添加或移除 Interceptor 来完成对不同参数在某一类型 controller 上的注入。
3. controller 的自定义上下文对象通过外界注入,测试时开发人员可以很容易地注入自己想要的自定义上下文对象。
4. controller 类去掉了对 Servlet API 的依赖,更贴近 POJO 和通用。
5. controller 类是通过对 interface 的声明来辅助完成注入的,并不存在任何继承依赖。
缺点:
1. SpringMVC 对 controller 默认是按照单例(singleton)处理的,在 controller 类中添加一个成员变量,可能会引起多线程的安全问题。不过我们可以通过声明@Scope(value="prototype")来解决;
2. 因为自定义上下文对象是定义为 controller 的成员变量,而且是通过 setter 注入进来,在测试时需要很小心地保证对controller 注入了自定义上下文对象,否则有可能我们拿到的就不一定是一个“好公民”(Good Citizen)。
三. 通过方法参数处理类(MethodArgumentResolver)在方法级别注入自定义上下文对象
正如前面所看到的,SpringMVC 提供了不少扩展点给开发人员扩展,让开发人员可以按需索取,plugin 上自定义的类或 handler。那么,在 controller 类的层次上,SpringMVC 提供了 Interceptor 扩展,在 action 上有没有提供相应的 handler 呢?如果我们能够对方法实现注入,出现的种种不足了。
通过查阅 SpringMVC API 文档,SpringMVC 其实也为方法级别提供了方法参数注入的 Resolver 扩展,允许开发人员给 HandlerMapper 类 set 自定义的 MethodArgumentResolver。
UserController类:
@Controller
@RequestMapping(value="/user")
@Scope(value="prototype")
public class UserController{
private static final Logger log = LoggerFactory.getLogger(UserController.class);
@Autowired
private IUserService service;
@RequestMapping(value="/get/{id}")
@ResponseBody
public User getUser(@PathVariable("id") String id, MyApplicationContext context){
log.info("Find user with id={}", id);
User user = null;
try {
user = service.findUserById(id);
if (user != null) {
context.setAttribute("currentUser", user);
}
} catch (Exception e) {
e.printStackTrace();
}
return (User) context.getAttribute("currentUser");
}
}
WebArgumentResolver接口实现类: