Spring MVC : ServletRequest 注入原理分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/andy_zhang2007/article/details/88315653

Spring应用中,将一个较大作用域的bean注入到一个较小作用域的bean中是很自然的一件事情,因为往较小作用域bean中注入较大作用域bean时,较大作用域的bean已经存在了。但是,如果反过来,将一个较小作用域的bean往一个较大作用域的bean中注入时,较小作用域的bean可能根本不存在,比如Spring MVC应用中,如果要将一个ServletRequest注入到一个单例作用域的Web控制器组件中,则该注入动作会在该单例Web控制器组件初始化时发生(容器对单例bean的创建过程决定的),而通常此时容器正在启动,任何用户请求尚未到达,所以注入任何一个ServletRequest听起来都是不正确的。以此类推,将一个较小作用域的bean往一个较大作用域的bean中注入概念上讲是不可行的。

但通过实践,我们明确知道,在一个Spring MVC应用中,将一个ServletRequest注入到一个单例作用域的Web控制器中是可以的。这又是为什么呢 ?这里面,我们有两个方面的问题要解答 :

  1. 注入的bean是什么?为什么ServletRequest能够注入成功 ?
  2. 注入的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方便调试模式下加断点观察注入的对象。

基于这个例子中,我们不难推断出如下结论,实际上也是事实 :

  1. 因为注解@Controller,容器中会有一个单例bean HomeController
  2. 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 : 为什么可以正确访问?

猜你喜欢

转载自blog.csdn.net/andy_zhang2007/article/details/88315653