2013-05-28 34 views
18

Nếu bạn sử dụng Spring MVC, các lớp thành phần của bạn (@Controller, @Service, @Repository) có phải là chủ đề an toàn không?Lớp Spring MVC phải là chủ đề an toàn

Tức là, nếu tôi có phương pháp @RequestMapping trong @Controller, phương pháp đó có thể được gọi đồng thời cho cùng một đối tượng bộ điều khiển bởi nhiều hơn một chuỗi không?

(Điều này có sort-of been asked before, nhưng không được trả lời như vậy).

+0

Về chỉnh sửa. Spring sẽ gọi cùng một phương thức trên cùng một cá thể lớp '@ Controller' cho một yêu cầu với cùng một định dạng được yêu cầu bởi' @ RequestMapping'. –

Trả lời

30

Với

@Controller 
public class MyController { 
    @RequestMapping(value = "/index") 
    public String respond() { 
     return "index"; 
    } 
} 

mùa xuân sẽ tạo ra một thể hiện của MyController. Điều này là do Spring phân tích cú pháp cấu hình của bạn, <mvc:annotation-driven>, xem @Controller (giống như @Component) và khởi tạo lớp chú thích. Bởi vì nó thấy @RequestMapping là tốt, nó tạo ra một HandlerMapping cho nó, xem docs here.

Mọi yêu cầu HTTP mà DispatcherServlet nhận sẽ được gửi đến trường hợp bộ điều khiển này qua HandlerMapping đã đăng ký trước đó, gọi respond() thông qua phản ánh java trên trường hợp đó.

Nếu bạn có instance fields như

@Controller 
public class MyController { 
    private int count = 0; 
    @RequestMapping(value = "/index") 
    public String respond() { 
     count++; 
     return "index"; 
    } 
} 

count sẽ là một mối nguy hiểm, bởi vì nó có thể được sửa đổi bởi nhiều chủ đề và thay đổi nó có thể bị mất.

Bạn cần hiểu cách các vùng chứa Servlet hoạt động. Vùng chứa này thể hiện một phiên bản của Spring MVC DispatcherServlet của bạn. Container cũng quản lý một nhóm các Threads mà nó sử dụng để trả lời các kết nối, ví dụ. Yêu cầu HTTP. Khi một yêu cầu đến, container chọn một Thread từ pool và, trong Thread đó, thực thi phương thức service() trên DispatcherServlet gửi đến đúng @Controller instance mà Spring đã đăng ký cho bạn (từ cấu hình của bạn).

Vì vậy, các lớp học Spring MVC phải là chủ đề an toàn. Bạn có thể làm điều này bằng cách chơi với các phạm vi khác nhau cho các trường thể hiện lớp của bạn hoặc thay vào đó chỉ có các biến cục bộ. Nếu không, bạn sẽ cần phải thêm đồng bộ hóa thích hợp xung quanh các phần quan trọng trong mã của bạn.

+0

"Mùa xuân sẽ tạo một thể hiện của MyController" (giả sử bạn chỉ có nghĩa là một ví dụ), bạn có thể cung cấp bất kỳ tài liệu chính thức nào về tuyên bố này không? Như tôi đã nhận xét trong câu trả lời khác, có vẻ như một số nhầm lẫn trong phần này. – kosa

+0

[tài liệu] chính thức (http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/mvc.html), nhưng không phải là một vị trí cụ thể. Hãy để tôi cập nhật câu trả lời. –

+0

@Nambari [đoạn này trong tài liệu] (http://static.springsource.org/spring/docs/3.0.0.M3/reference/html/ch04s04.html # beans-factory-scopes-singleton) nói là hoàn toàn: 'Phạm vi singleton là phạm vi mặc định trong Spring' – soulcheck

-1

Có, tất nhiên.

Tốt nhất là những người không có quốc tịch, điều này làm cho chúng an toàn theo mặc định. Nếu không có chia sẻ, trạng thái có thể thay đổi sẽ không có vấn đề gì.

+6

"tất nhiên": Tôi không nghĩ điều đó quá hiển nhiên đối với người mới bắt đầu. Chăm sóc để mở rộng một chút? – Raedwald

+0

@Raedwalk Spring chỉ tạo một cá thể (theo mặc định) của các lớp 'Thành phần' của bạn, vì vậy tất cả các trường cá thể của chúng sẽ được chia sẻ cho mỗi yêu cầu. –

+0

Vài ngày trước, tôi thấy phản ứng ngược lại từ một trong những người đóng góp SO có kinh nghiệm. Phản hồi là, "mỗi yêu cầu sẽ có thể hiện riêng của nó về các thành phần này" (Khác với kiến ​​trúc HTTPServlet). Tôi đồng ý "Tốt nhất nếu những người đó không có quốc tịch, điều này khiến họ an toàn theo mặc định", nhưng sẽ rất tuyệt nếu có bất kỳ tài liệu chính thức nào về "một thành phần của" thành phần. – kosa

0

Theo mặc định, bộ điều khiển là đơn và do đó phải an toàn chỉ. Tuy nhiên, bạn có thể cấu hình các bộ điều khiển được yêu cầu hoặc phiên scoped, tức là .:

@Controller 
@Scope("session") 
public class MyController { 

    ... 
} 

Controller với phiên phạm vi có thể hữu ích để quản lý trạng thái phiên. Bạn có thể tìm thấy mô tả tốt về các mẫu khác nhau trong Using Sessions in Spring-MVC (including "scoped-proxies") và trong How to get Session Object In Spring MVC. Một số mẫu được trình bày yêu cầu phạm vi yêu cầu.

Phạm vi yêu cầu cũng hữu ích nếu bạn có dữ liệu mà bạn không thể tính toán nhiều hơn một yêu cầu.

+0

Xin chào. Tôi đến đây và thấy điều này hữu ích. Nhưng bạn có thể cho tôi biết, nếu có rất nhiều người dùng nói một số hàng trăm hoặc hàng nghìn. Điều đó có nghĩa là chúng ta sẽ có rất nhiều bộ điều khiển? Hãy giúp tôi! @codo –

+1

Tôi đoán vậy. Nếu không nó sẽ không hoạt động. Nếu bạn cần dữ liệu phiên, bạn chắc chắn sẽ kết thúc với cấu trúc dữ liệu cho mỗi người dùng trong bộ nhớ. – Codo

-1

Về cơ bản, câu trả lời phải có và không. Ngoại trừ lý do rất nghiêm trọng. Không phải vì Spring đồng bộ hóa công việc cho bạn - nó không làm việc đó (theo mặc định một Controller là một bean Singleton). Sự an toàn chủ đề thô phải được giữ lại theo một cuộc gọi phương thức, nhưng cơ chế thông thường của Servlets sẽ xóa bỏ sự cần thiết phải đồng bộ hóa một cái gì đó, bởi vì một yêu cầu được thực hiện bên trong một luồng. Vì vậy, trong suốt cuộc gọi của bất kỳ phương thức chú thích @RequestMapping nào, toàn bộ cuộc gọi được thực thi trong một luồng. Trong thư mục gốc, nó được gửi đi từ các phương thức dịch vụ (Get, Post ..) của Servlet và sau đó các bản đồ xử lý được xử lý, mà Spring xây dựng (xem ví dụ http://www.studytrails.com/frameworks/spring/spring-mvc-handler-mappings/http://technicalstack.com/dispatcher-servlethandlermapping-controller/). Spring gọi phương thức xử lý từ bản đồ các trình xử lý, sau khi URL đã được giải quyết. Không có thủ thuật nào khác. Vì vậy, suy nghĩ, bạn làm việc bên trong một doPost (...) ví dụ phương thức của DispatchServlet. Chủ đề Servlet có an toàn không? Không thô. Bạn có thể làm chủ đề an toàn, có, sử dụng khóa, đồng bộ, những gì khác và làm cho Servlet của bạn trở thành một nút cổ chai! Chính xác như vậy là về bộ điều khiển. Phương thức doGet/Post/phương thức Servlet khác có về cơ bản là một mô hình chức năng, tất cả các dữ liệu đều nằm trong đối tượng HttpServletRequest. Cách thức tương tự nên được sử dụng trong các lớp dữ liệu do đối tượng điều khiển sử dụng và ngăn xếp thay vì các trường. Bạn có thể đồng bộ hóa quyền truy cập vào chúng, nhưng bằng cách trả giá của nút cổ chai. Của thô bạn có thể sử dụng nguyên tử, bởi vì nó là cần thiết? Nếu bạn cần giữ trạng thái bất kỳ trong phiên, bạn có thể sử dụng @Scope ("phiên") sau @Controller hoặc (đối với điều khiển singleton) một phương thức xử lý có chữ ký (..., HttpSession) cả hai đều có ưu và khuyết điểm. Nhưng lưu ý rằng bạn đã tạo thêm chi phí CPU và GC. Dù sao, bạn chịu trách nhiệm về sự an toàn của luồng Bộ điều khiển khi bạn muốn sử dụng các trường và thoát khỏi khái niệm vô quốc gia. Thông thường, bộ nhớ cache (ví dụ redis) thích hợp hơn cho trạng thái máy khách. Ít nhất bạn có thể khôi phục trạng thái khi xảy ra lỗi. Bộ điều khiển stateful trong phạm vi phiên cơ bản không có lý do.

Các vấn đề liên quan