搜尋

首頁  >  問答  >  主體

java - Springmvc中在controller注入request会有线程安全问题吗

@Controller
public class AController{

    @Autowire
    HttpServletRequest request;
    
    @RequestMapping("/test")
    public Result test(){
        System.out.println(request.toString());
        request.getHeader("uid");
    }
}

例如上述代码,
我使用Autowire注入request后,直接在controller的方法中使用request
由于controller默认是单例的,我在想是否会有线程安全问题。
因为我输出了requesthashcode发现每次请求hashcode都是一样的。
那么后面的request是否会覆盖当前request导致信息失真?

·····························补充··························

1、我想在controller的每个方法里都使用HttpServletRequest,那么每次在方法里都要声明我觉得就比较麻烦了?不知道大家怎么解决这个问题?
2、我这样写的原因是,我想通过继承一个父类的方式,让request作为父类的一个成员变量,这样可以在方法里直接使用。
3、我通过楼下叉叉哥的方式(之前就是这样写的)

public Result test(HttpServletRequest request){

    System.out.println(request.toString());
}

同样不断访问,或者用不同客户端访问。发现打印出来的每个请求的request的hashcode居然也是相同的,为什么?

高洛峰高洛峰2887 天前571

全部回覆(10)我來回復

  • 巴扎黑

    巴扎黑2017-04-17 17:59:04

    謝謝大家的回答
    經過我的測試和探索。
    的結論是
    使用@autowire注入HttpServletRequest是線程安全的。
    具體驗證過程我寫了篇blog
    有興趣的可以看看,如果有什麼不對的地方,請大家指出來。
    再次感謝樓上熱心回答我問題的程式設計師

    blog地址戳我

    ps:以上討論的都是Controller為單例模式下的

    ···

    回覆
    0
  • 大家讲道理

    大家讲道理2017-04-17 17:59:04

    首先,原則上 Request 不可以定義為 Controller 的成員,因為二者的生命週期實在是完全脫節的,這樣子弄只會造成 Controller 無法呼叫到正確的 Request 物件。

    其次 @Autowire 是一次性賦值的,而 Request 物件有無數多個,所以你這樣寫的話,Spring 也會不知該如何是好。因為應用程式啟動的時候根本沒有 Request 對象,所以這樣應該會導致啟動失敗。

    回覆
    0
  • PHP中文网

    PHP中文网2017-04-17 17:59:04

    額,我獻醜了,光顧著解決次要的request每次相同的问题了,忘了主题了。
    @ModelAttribute確實會有線程安全問題!
    ...

    在要使用物件屬性,的情況下還處理線程安全的話,有一種方法很簡單,但是特別糙,直接使用@Scope("prototype")讓Spring MVC每次請求都產生一個新的實體類別... @Scope("prototype")让Spring MVC每次请求都生成一个新的实体类...
    但Spring MVC为什么默认要单例?自然是因为单例的性能和开销的优点,
    而写@Scope("prototype")但Spring MVC為什麼預設要單例?自然是因為單例的效能和開銷的優點,

    而寫@Scope("prototype")之後就意味著放棄單例的優點。

    所以這確實是一種方式,但是並不好,給各位獻醜了,抱歉。 🎜
    @Controller
    // @Scope("prototype")
    public class AController{
    
        //@Autowired //如果采用非单例模式的话,用autowried也一样。
        protected HttpServletRequest request;
        protected HttpServletResponse response;
        
        @ModelAttribute
        public void bindRequestObject(HttpServletRequest request, HttpServletResponse response) {
            this.request = request;
            this.response = response;
        }
        
        @RequestMapping("/test")
        public Result test(){
            System.out.println(request.toString());
            request.getHeader("uid");
        }
    }

    回覆
    0
  • 迷茫

    迷茫2017-04-17 17:59:04

    1、Autowire注入request後,使用實例變數會有安全性問題
    2、會覆寫request
    3、hashcode相同還是一個物件

    覺的方法中寫參數麻煩,這樣可以:

    @Controller
    public class AControllre extends AbstractController {
    
        @RequestMapping("/test")
        public String test(){
            //使用
            String name = getRequest().getParameter("username");
            return "";
        }
    }
    
    class AbstractController {
        protected HttpServletRequest getRequest() {
            return ((ServletRequestAttributes) 
                    RequestContextHolder.getRequestAttributes()).getRequest();
        }
        protected HttpServletResponse getResponse() {
            return new ServletWebRequest(((ServletRequestAttributes) 
                    RequestContextHolder.getRequestAttributes()).getRequest()).getResponse();
        }
    }

    回覆
    0
  • PHPz

    PHPz2017-04-17 17:59:04

    第一次看過這種寫法,為什麼不這樣寫?

    @Controller
    public class AController{
        
        @RequestMapping("/test")
        public Result test(HttpServletRequest request){
            System.out.println(request.toString());
            request.getHeader("uid");
        }
    }

    實際上在大部分情況下,request都不用作為參數傳過來的,例如你想拿到請求頭中的uid,可以這樣寫:

    @Controller
    public class AController{
        
        @RequestMapping("/test")
        public Result test(@RequestHeader("uid") String uid) {
            System.out.println(uid); // 相当于request.getHeader("uid")
        }
    }

    回覆
    0
  • 阿神

    阿神2017-04-17 17:59:04

    你那樣寫肯定是會發生線程安全問題的,因為 spring 的每個 controller 默認都是單例的,所以你的 request 會被其他線程給共享,所以建議你和 @叉叉哥 寫法一樣。

    回覆
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-17 17:59:04

    會有的。在Servlet裡,都是把屬性參數寫在方法裡,這樣就不會被共用

    回覆
    0
  • PHP中文网

    PHP中文网2017-04-17 17:59:04

    你這樣寫一定會有線程安全問題,因為controller預設是單例的,說明多次請求會共享一個HttpServletRequest對象,加上@Scope("prototype")就沒有問題了

    回覆
    0
  • PHP中文网

    PHP中文网2017-04-17 17:59:04

    會有線程安全問題的,建議你看看這篇文章http://www.xuebuyuan.com/1628190.html

    回覆
    0
  • 巴扎黑

    巴扎黑2017-04-17 17:59:04

    任何類別實例變數都有潛在的執行緒安全的風險,程式碼需要確保該實例變數在多執行緒下沒問題,或確保該類別同時只有一個執行緒存取。
    你這個例子多執行緒的問題是必然的,你還是根據Spring的教學按照標準的寫法寫,先把事情搞對了,理解了,然後再搞複雜的。

    回覆
    0
  • 取消回覆