Avatar
0
tvd12 Enlightened
tvd12 Enlightened
Spring: singleton có ý nghĩa gì và tại sao lại phải tạo singleton?
Em chào anh.

Em mới mua sách "Làm chủ các mẫu thiết kế kinh điển trong lập trình" của anh. Em thấy ngay phần đầu tiên anh có đề cập đến singleton. Em mới chuyển ngành sang làm dev có một câu hỏi mong anh có thế giải thích ạ.

Trong Spring Boot singleton được tạo ra nếu đánh dấu nó là 1 bean, vậy singleton có ý nghĩa gì và tại sao lại phải tạo singleton. Để hiểu cách nó tạo ra thì làm như thế nào được ạ?

  • Answer
Remain: 5
1 Answer
Avatar
tvd12 Enlightened
tvd12 Enlightened
Hãy nói em có một lớp UserService thế này:
public class UserService {
  public User getUserById(long userId) {
    // trả về user theo id
  }
}

Tiếp theo chúng ta sẽ có một lớp là UserController để xử lý yêu cầu lấy thông tin người dung, Nếu bây giờ không sử dụng singleton thì mã nguồn sẽ như sau:

public class UserController {
  @GetMapping("/users/{userId}")
  public User getUserById(@PathVariable long userId) {
    UserService service = new UserService();
    return userService.getUserById(userId);
  }
}

Trên thực tế trong một thời điểm UserController có thể phải xử lý rất nhiều yêu cầu, vậy mỗi yêu cầu lại sinh ra một đối tượng UserService, điều này làm tăng bộ nhớ cần tạo, ngoài ra gây ra tình trạng cấp, giải phóng bộ nhớ liên tục sẽ làm tiêu tốn cả tài nguyên CPU nữa.

Ngoài ra trên thực thế lớp UserService có thể phụ thuộc vào các lớp khác như UserRepository, như vậy thì việc khởi tạo sẽ cực kỳ phức tạp. Như vậy cần thiết phải sử dụng singleton để khởi tạo duy nhất một đối tượng cho lớp UserService để tiết kiệm tài nguyên, đồng thời cũng dễ dàng hơn trong việc khởi tạo các lớp phụ thuộc lẫn nhau, giải phóng lập trình viên khỏi việc khởi tạo các đối tượng để xử lý.

Spring sử dụng reflection để quét các lớp trong package được chỉ định, sau đó cũng khởi tạo và inject các đối tượng phụ thuộc sử dụng reflection. Để tìm hiểu sâu vào bên trong thì chỉ có đọc source code của spring-context thôi em ạ.

  • 0
  • Reply
bố sung thêm 1 ví dụ khác sử dụng Dependency Injection (DI). tránh việc khởi tạo quá nhiều instance và khi nó không được sử dụng hoặc không có tham chiến thì sẽ trở thành "rác" (garbage). Trình quản lý bộ nhớ tự động (garbage collector) của Java sẽ quản lý và thu gom các đối tượng rác này. Nếu có quá nhiều rác thì sẽ dẫn đến : 1.Tiêu tốn tài nguyên bộ nhớ: Mỗi instance sẽ tiêu tốn một lượng tài nguyên bộ nhớ. Nếu tạo quá nhiều instance mà không giải phóng chúng, ứng dụng có thể tiêu tốn nhiều bộ nhớ hơn cần thiết, dẫn đến hiện tượng tốn tài nguyên và giảm hiệu suất.2.Hiệu suất kém: Nếu tạo quá nhiều instance và không quản lý chúng, có thể dẫn đến hiệu suất kém do overhead khi sử dụng bộ nhớ, sự cạnh tranh về tài nguyên bộ nhớ và thời gian cần thiết để garbage collector làm việc.3.Lỗi OutOfMemoryError: Nếu ứng dụng tạo quá nhiều instance và không giải phóng bộ nhớ đúng cách, nó có thể gây ra lỗi OutOfMemoryError, làm ứng dụng bị crash.
@Service
public class UserService {
    public User getUserById(long userId) {
        // Trả về user theo id
    }
}

@Controller
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping("/users/{userId}")
    public User getUserById(@PathVariable long userId) {
        return userService.getUserById(userId);
    }
}
 –  PhuongPyke 1698111785000