在Spring应用中,将一个较大作用域的bean注入到一个较小作用域的bean中是很自然的一件事情,因为往较小作用域bean中注入较大作用域bean时,较大作用域的bean已经存在了。但是,如果反过来,将一个较小作用域的bean往一个较大作用域的bean中注入时,较小作用域的bean可能根本不存在,比如Spring MVC应用中,如果要将一个ServletRequest注入到一个单例作用域的Web控制器组件中,则该注入动作会在该单例Web控制器组件初始化时发生(容器对单例bean的创建过程决定的),而通常此时容器正在启动,任何用户请求尚未到达,所以注入任何一个ServletRequest听起来都是不正确的。以此类推,将一个较小作用域的bean往一个较大作用域的bean中注入概念上讲是不可行的。
但通过实践,我们明确知道,在一个Spring MVC应用中,将一个ServletRequest注入到一个单例作用域的Web控制器中是可以的。这又是为什么呢 ?这里面,我们有两个方面的问题要解答 :
- 注入的
bean是什么?为什么ServletRequest能够注入成功 ? - 注入的
bean如何工作的?为什么请求过程中访问注入的ServletRequest能访问到正确的信息?
为了解答上面两个问题,我们准备了一个例子演示ServletRequest的注入。该例子如下:
@Controller
public class HomeController {
ServletRequest request;
@Autowired
public void setRequest(ServletRequest request){
this.request=request;
}
@RequestMapping("/")
@ResponseBody
public String home() {
return "Hello "+ request.getParameter("name");
}
}
这是Spring MVC项目中的一个Web控制器类HomeController,使用了注解@Controller。另外这里在setRequest
方法上使用注解@Autowired方便调试模式下加断点观察注入的对象。
基于这个例子中,我们不难推断出如下结论,实际上也是事实 :
- 因为注解
@Controller,容器中会有一个单例bean HomeController, request是单例bean HomeController的属性,所以该属性会在bean HomeController创建过程中注入。
换句话讲,此时request对象必须已经存在并且作用域不能小于bean HomeController的作用域。
另外我们也希望 : 每次替换不同的参数值{name}访问首页http://localhost:8080?name={name}时,request总是表示针对该次访问的请求。实际上这也是事实:
http://localhost:8080/?name=John ==对应输出==> Hello John
http://localhost:8080/?name=Snow ==对应输出==> Hello Snow
到这里,我们的问题就凸显出来了 : bean HomeController创建时还没有任何请求发生,也无法预知会发生什么样的请求,但注入的该request对象在请求发生时却能正确地访问到用户请求,那么,该现象背后到底是怎么回事呢 ?
接下来,基于上述例子,我们将分两部分分析现象背后的工作原理,进而你可以举一反三地思考将一个较小作用域的bean往一个较大作用域的bean中进行注入的可行性:
Spring MVC : ServletRequest 注入原理分析 1 : 为什么可以注入成功?
Spring MVC : ServletRequest 注入原理分析 2 : 为什么可以正确访问?
本文探讨了在SpringMVC应用中,如何将较小作用域的bean如ServletRequest注入到较大作用域的bean中,如单例作用域的Web控制器。通过分析HomeController类的实例,解释了在不同请求下,每次都能正确获取请求参数的原理。
1055

被折叠的 条评论
为什么被折叠?



