V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
twofox
V2EX  ›  Java

Controller 和 Service 中注入 HttpServletResponse 有什么差异吗

  •  
  •   twofox · 86 天前 · 1458 次点击
    这是一个创建于 86 天前的主题,其中的信息可能已经有所发展或是发生改变。

    项目里需要导出一个文件。一开始我使用的在 Service 的实现类里面注入 response

    //serviceImpl
    
    //服务类注入
    @Autowired
    private HttpServletResponse response;
    
    
    public void export(params){
        // ...
    }
    
    

    然后就很常规的打开流,获取文件,写入,关闭 但是无法通过项目的网关鉴权,报了一个 null 错误。

    但是如果是在 controller 里面注入,再直接传给 Service ,就可以通过鉴权。 就像这样。

    //Controller 注入
    
    @Autowired
    private HttpServletResponse response;
    
    public void export(params){
    
    	//传给 service
        
    	exportSevice.export(params, response);
    }
    
    

    请问这两种方式注入的差别在哪?

    18 条回复    2022-04-28 09:21:30 +08:00
    chendy
        1
    chendy  
       86 天前   ❤️ 1
    service 层不应该依赖 HttpServletResponse
    应该是 controller 层接 HttpServeltResponse ,serivce 层接 OutputStream

    至于鉴权啥的只能说不了解,但是这个注入方法真的有点厉害……梦回 struts2 了
    darkengine
        2
    darkengine  
       86 天前
    service 的实现类前有没有加 @ Component 注解?
    zmal
        3
    zmal  
       86 天前
    response 也能注入啊,还真不知道...
    paradoxs
        4
    paradoxs  
       86 天前
    为啥要这样注入
    shanghai1943
        5
    shanghai1943  
       86 天前
    这也能注入。。涨知识了。。
    TWorldIsNButThis
        6
    TWorldIsNButThis  
       86 天前
    为什么注入成成员变量,不是应该是方法参数吗
    不同请求过来每次都会改这个字段?
    wolfie
        7
    wolfie  
       86 天前   ❤️ 1
    struts2 写法,strut2 升级到 springmvc 时候,不少架构这么玩,配合 spring 默认单例 可能串会话。
    night98
        8
    night98  
       86 天前   ❤️ 1
    信息量太少,简单说一下,controller 是注入在 springmvc 容器里的,所以应该可以正常拿到 response ,service 层用的 spring 容器,所以拿不到,会报 null 异常,至于鉴权应该是在 request 期间鉴权的,大致应该是这样子的,
    EscYezi
        9
    EscYezi  
       85 天前 via iPhone   ❤️ 1
    还真没在成员变量注入过 response ,不过想了想都是单例,并发可能会有问题吧?
    twofox
        10
    twofox  
    OP
       85 天前
    @chendy 因为这是公司的项目。。同个 service 里面有类似的写法,为了保持风格一致我就这么写了。service 层确实不应依赖 Response ,我写自己的项目的时候都是传参进去的=.=


    @darkengine 加了 @Service 注解


    @TWorldIsNButThis 可能是为了少写个参数?


    @night98 很有可能,下班了试一下
    cnzjl
        11
    cnzjl  
       85 天前
    啊,我刚入行的时候就是这么注入的,比较方便
    nothingistrue
        12
    nothingistrue  
       85 天前   ❤️ 1
    HttpServletResponse 是绑定当前连接的有状态对象,Service 通常是无状态 Bean ,Controller 通常是( Spring MVC 就绝对是)有状态 Bean ,因此,HttpServletResponse 注入 Controller (的成员)没问题,注入 Service (的成员)会产生严重问题。

    你如果注入 Service ,那么第一个请求来了会把当前请求的 HttpServletResponse 注入单例的 Service 。单例的 Service 中的这个成员,一旦注入过就不会再重新注入了,以后所有的请求调用的 Service ,使用的都是第一个请求的 HttpServletResponse 。这个 HttpServletResponse 对象本身因为还被引用着不会被回收,但它里面引用的其他对象,会在第一个请求完成之后就销毁,于是后面就会出现 NullPointException 。


    最后说一点,exportSevice.export(params, response) 这样的方法,即把依赖对象通过方法参数传入,不是用 Spring 实现的依赖注入,但它也是依赖注入。
    twofox
        13
    twofox  
    OP
       85 天前
    @nothingistrue 那正确的写法呢?
    exportSevice.export(params, response.getOutputStream())
    nothingistrue
        14
    nothingistrue  
       85 天前   ❤️ 1
    你的第二次使用已经正确了:注入到 Controller ,再传递给 Service 。Controller 是非单例的有状态 Bean ,可以注入 HttpServletResponse 。 @twofox

    其实对于 HttpServletResponse 这种跟当前请求绑定的对象,最好全程通过方法参数注入,不要将他注入到类的成员变量上。Spring MVC 中,如果把 HttpServletResponse 作为 Controller 的方法的参数,不需要加 Autowired 它都是自动注入的。
    codergrowing
        15
    codergrowing  
       85 天前
    @nothingistrue #14 「 Controller 是非单例的有状态 Bean 」?不对吧,Controller 默认应该也是单例的。
    nothingistrue
        16
    nothingistrue  
       84 天前
    @codergrowing #15 可能我记错了,不过 Spring Boot 之后,Spring MVC 部分推荐的都是通过方法参数注入,已经基本不用成员变量注入了,这种注入单例非单例都没区别。一般来说,从 Struts2 之后,控制器部分都是单例的,可能 Spring MVC 发现没有成员变量注入之后会自动优化成单例模式。
    twofox
        17
    twofox  
    OP
       84 天前
    @nothingistrue 感谢答疑!
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1737 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 17:03 · PVG 01:03 · LAX 10:03 · JFK 13:03
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.