java - Springmvc中在controller注入request会有线程安全问题吗
高洛峰
高洛峰 2017-04-17 17:57:04
0
10
563
@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居然也是相同的,为什么?

高洛峰
高洛峰

拥有18年软件开发和IT教学经验。曾任多家上市公司技术总监、架构师、项目经理、高级软件工程师等职务。 网络人气名人讲师,...

reply all(10)
巴扎黑

Thank you everyone for your answers
After my testing and exploration.
The conclusion is that
using @autowireinjecting HttpServletRequest is thread-safe.
I wrote a blog about the specific verification process
If you are interested, you can read it. If there is anything wrong, please point it out.
Thank you again to the programmers upstairs who enthusiastically answered my questions

Click me for blog address

ps: The above discussion is all about Controller in singleton mode

···

大家讲道理

First of all, in principle, Request cannot be defined as a member of Controller, because the life cycles of the two are completely disconnected. This will only cause the Controller to be unable to call the correct Request object.

Secondly, @Autowire is assigned once, and there are countless Request objects, so if you write it like this, Spring will not know what to do. Because there is no Request object when the application starts, this should cause the startup to fail.

Ty80

Um, I'm showing off my shame, just focusing on solving minor issuesrequest每次相同的问题了,忘了主题了。
@ModelAttributeIt is truethat there will be thread safety issues!
...

If you want to use object properties and handle thread safety, there is a method that is very simple, but particularly rough. Directly use @Scope("prototype") to let Spring MVC request each time A new entity class is generated... @Scope("prototype")让Spring MVC每次请求都生成一个新的实体类...
但Spring MVC为什么默认要单例?自然是因为单例的性能和开销的优点,
而写@Scope("prototype")But why does Spring MVC require a singleton by default? Naturally, because of the performance and cost advantages of singletons, writing @Scope("prototype") means giving up the advantages of singletons.

So this is indeed a way, but it’s not good. It’s embarrassing for everyone, I’m sorry.

@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");
    }
}
迷茫

1. After Autowire injects the request, there will be security issues when using instance variables.
2. The request will be overwritten. 3. The hashcode is still the same object.

It seems troublesome to write parameters in the method, so you can:

@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();
    }
}
PHPzhong

This is the first time I have seen this way of writing. Why not write it like this?

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

In fact, in most cases, request does not need to be passed as a parameter. For example, if you want to get the uid in the request header, you can write like this:

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

If you write it that way, thread safety issues will definitely occur, because each controller in spring is singleton by default, so your request will be shared by other threads, so it is recommended that you write it in the same way as @ChaCha哥.

伊谢尔伦

There will be. In Servlet, attribute parameters are written in the method so that they will not be shared

洪涛

If you write like this, there will definitely be thread safety issues, because the controller is a singleton by default, which means that multiple requests will share an HttpServletRequest object. If you add @Scope("prototype"), there will be no problem

Ty80

There will be thread safety issues, I suggest you read this article http://www.xuebuyuan.com/1628190.html

巴扎黑

Any class instance variable has potential thread safety risks. The code needs to ensure that the instance variable is ok under multi-threading, or ensure that the class is accessed by only one thread at the same time.
The problem of multi-threading in your example is inevitable. You should follow the Spring tutorial and write it in the standard way. Get things right and understand them first, and then move on to complicated ones.

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template