Vì sao không nên dùng field injection trong spring

Nội dung bài viết

Chào bạn, chắc hẳn bạn cảm thấy khó hiểu về Dependency Injection [DI] là gì đúng không? Có phải bạn không rõ khái niệm của nó trong lập trình? Tại sao chúng ta cần DI? Các loại DI có trong lập trình? Và cuối cùng là lợi ích khi sử dụng Dependency Injection.

1 .Dependency Injection là gì

Trước hết mình hãy phân tích từ Dependency [phụ thuộc] nghĩa là gì? Anh lấy ví dụ trong thực tế. Khi mình đi làm thì mình có thể dùng phương tiện di chuyển là xe máy để đến công ty. Như vậy để đạt được mục đích đến công ty thì anh phải bắt buộc có chiếc xe máy để hoàn thành nhiệm vụ của mình. Như vậy anh đang phụ thuộc vào chiếc xe máy để đạt được mục đích là đến công ty.

Tương tự như vậy trong lập trình, ví dụ anh viết một chức năng cho giáo viên có thể xem kết quả điểm thi của từng học sinh. Như vậy trong lớp giáo viên, anh phải có đối tượng sinh viên để anh có thể lấy được kết quả thi của bạn sinh viên đó. Như vậy lớp giáo viên phụ thuộc vào lớp sinh viên vì nếu không có đối tượng sinh viên được khai báo trong lớp giáo viên, thì giáo viên không thể lấy được điểm của sinh viên.

Ví dụ trong Java mình có lớp Student như sau. Gồm có tên [name], điểm thi [mark] và mình có phương thức getStudentMark[] để lấy kết quả thi của sinh viên.

1 2 3 4 5 6 7 8 9 10 11 12 public class Student { private String name; private float mark; public Student[]{ } public float getStudentMark[] { return mark; } }

Ví dụ chúng ta có lớp Teacher như sau. Gồm có tên và phương thức getStudentMark[] để lấy ra điểm thi của Sinh Viên.

1 2 3 4 5 6 7 8 9 10 11 12 public class Teacher { private String name; private Student student; public Teacher[]{ student = new Student[] } public float getStudentMark[] { return student.getStudentMark[]; } }

Như các bạn thấy trong lớp Teacher dòng số 6. Mình khai báo đối tượng Student trong lớp Teacher để mình có thể sử dụng được phương thức getStudentMark[] phục vụ cho việc xem điểm của giáo viên.

Tiếp đến mình đi tìm hiểu khái niệm Injection là gì? Như các bạn thấy tại dòng số 6 của class Teacher. Để sử dụng được chức năng getStudentMark[] trong đối tượng sinh viên thì mình phải sử dụng toán tử new để tạo ra đối tượng Student trước khi sử dụng các phương thức có trong Student. Vậy có thể hiểu Injection là mình giao cho một ai đó [ví dụ spring framework chẳng hạn] khởi tạo object và nhúng object đó và các Dependency đang dùng.

Nói cách khác, ở ví dụ trên mình giao cho framework [Spring] khởi tạo đối tượng Student và nhúng đối tượng Student vào đối tượng Teacher mà ta không cần dùng toán tử new mà giao cho Spring quản lý.

2. Tại sao chúng ta cần Dependency Injection

  • Giảm sự phụ thuộc giữa các module, object giúp cho việc mở rộng code sau này của ta được dễ dàng.
  • Do các module, object là độc lập nên ta có thể viết unit test dễ dàng cho từng module.
  • Giúp chúng ta tập trung vào việc viết logic business [nghiệp vụ] của ứng dụng còn việc tạo và quản lý các đối tượng mình giao cho framework lo.

3. Các loại DI có trong lập trình

Có 3 cách để chúng ta có thể Dependency Injection [nhúng một object vào một object khác].

  • Thông qua constructor.
  • Thông qua setter và getter method.
  • Thông qua interface.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Teacher { private Student student; // Dựa vào constructor Teacher [Student student] { this.student = student; } // Dựa vào Setter method void setStudent[Student student]{ this.student = student; } }

4. Dependency Injection trong Spring

Trong dự án Spring chúng ta có thể nhúng đối tượng Student vào đối tượng Teacher như sau.

1- Sử dụng XML configuration

1 2 3 4

2- Sử dụng Annotation @autowire.

1 2 3 4 public class Teacher { @Autowired private Student student; }

5. Nói tóm lại nhiệm vụ của Dependency Injection

  • Tạo đối tượng.
  • Biết được class nào cần đối tượng đó mà nhúng vào. Trong dự án Spring thì mình có Spring Container sẽ giúp mình việc tạo các beans, quản lý vòng đời các beans. Biết được các beans nào phụ thuộc vào các beans nào mà Spring sẽ tự động nhúng các bean phụ thuộc vào. Nhờ có Dependency Injection mà lập trình viên chỉ quan tâm đến việc thực hiện các nghiệp vụ của ứng dụng và giao cho spring container việc quản lý các beans.

6. Video Demo

7. Source code

Mọi người hãy Subscribe kênh youtube dưới đây nhé để cập nhật các video mới nhất về kỹ thuật và kỹ năng mềm

Trong bài trước đã có bạn hỏi về cấu trúc các module trong Spring, đây chính là hình minh họa.

Trong phần này, chúng ta sẽ lần lượt nói về Spring Beans, Spring Annotations.

Spring Beans

21. Spring beans là gì?

Spring Beans chính là những Java Object mà từ đó tạo nên khung sườn của một Spring application.Chúng được cài đặt, lắp ráp và quản lý bởi Spring IoC container. Những bean này được tạo ra bởi configuration metadata được cung cấp từ container, ví dụ, trong tag nằm trong file XML.

Các bean được define trong spring framework là singleton bean. Có một thuộc trính trong bean với tên là “singleton” nếu được gán giá trị là true thì bean đó sẽ trở thành singleton, nếu là false thì bean đó sẽ trở thành prototype bean. Mặc định nếu không được định nghĩa giá trị của nó sẽ là true. Vì thế tất cả các bean trong spring framework mặc định sẽ là singleton bean.

22. Định nghĩa Spring bean gồm những gì?

Một Spring bean definition chứa tất cả các configuration metadata cái mà cần cung cấp cho container biết làm sao để tạo ra bean, cũng như chi tiết về lifecycle và những depedencies của nó.

23. Làm sao để cung cấp configuration metadata cho Spring Container?

Có ba cách để cũng cấp configuration metadata cho Spring container.

  • Thông qua XML configuration file
  • Thông qua Annotation-based configuration
  • Thông qua Java-based configuration

24. Làm sao để định nghĩa scope của bean?

Khi định nghĩa một bean trong Spring, chúng ta còn phải định nghĩa scope của bean. Việc định nghĩa scope có thể thực hiện thông qua việc sử dụng thuộc tính tên là “scope” khi định nghĩa. Lấy ví dụ, khi bean phải tạo mới mỗi lần cần sử dụng, thuộc tính scope sẽ là “prototype”. Mặt khác, khi bean luôn luôn trả về một instance giống nhau khi sử dụng, thuộc tính scope sẽ là “singleton”.

25. Các scope của bean

Spring framework đưa ra năm scope của bean như sau:

  • singleton: cho biết bean đó có một instance duy nhất trong Sping IoC container.
  • prototype: cho biết bean đó được định nghĩa là có nhiều object instances, mỗi lần muốn sử dụng sẽ tạo mới.
  • request: cho biết bean được định nghĩa với một HTTP request. Scope này chỉ hợp lệ khi chúng ta sử dụng Web Application Context.
  • session: cho biết bean được định nghĩa với một HTTP session. Scope này cũng chỉ hợp lệ khi chúng ta sử dụng Web Application Context.
  • global-session: cho biết bean được định nghĩa với một global HTTP session. Scope này cũng chỉ hợp lệ khi chúng ta sử dụng Web Application Context.

Scope mặc định của mọi Spring Bean là singleton.

26. Singleton Bean có Thread safe trong Spring Framework?

Không, trong Spring framework, singleton bean không thread safe.

27. Bean lifecycle trong Spring framework

  • Spring container tìm các bean definition trong file XML và khởi tạo các bean.
  • Spring cài đặt tất cả các thuộc tính được định nghĩa trong bean definition [Dependency Injection].
  • Nếu bean implement BeanNameAware interface, spring sẽ truyền bean id vào trong hàm setBeanName[].
  • Nếu bean implement BeanFactoryAware interface, spring sẽ truyền beanfactory vào hàm setBeanFactory[].
  • Nếu có bất cứ bean BeanPostProcessors nào được liên kết với bean đang khởi tạo, spring sẽ gọi hàm postProcesserBeforeInitialization[] và postProcessAfterInitialization[].
  • Nếu bean implement InitializingBean, phương thức afterPropertySet[] sẽ được gọi. Nếu bean đã được khai báo phương thức khởi tạo, thì phương thức đó sẽ được gọi.
  • Nếu bean implement DisposableBean interface, phương thức destroy[] sẽ được gọi.

28. Phương thức nào là quan trọng nhất trong Spring Bean lifecycle

Có hai phương thức quan trọng nhất trong Spring bean lifecycle. Đầu tiên đó là setup[], phương thức nay được gọi khi bean được load vào container. Phương thức thứ hai đó là teardown[], phương thức này được gọi khi bean được unload khỏi container.

Tag có hai thuộc tính quan trọng là init-methoddestroy-method với thuộc tính này, chúng ta có thể khai báo tùy biến phương thức khởi tạo và destroy cho mỗi bean. Ngoài ra nếu bạn sử dụng Annotation-based thì Spring framework cũng cung cấp hai annotation là @PostConstruct và @PreDestroy

29. Inner bean trong Spring

Khi mà bean chỉ được sử dụng như một thuộc tính của một bean khác thì nó được gọi là inner bean. XML-based configuration metadata cung cấp cho chúng ta sử dụng tag bên trong tag hoặc để khai báo gọi inner bean. Inner bean luôn luôn là anonymous và scope của chúng luôn là prototype.

30. Làm sao để inject Java Collection trong Spring?

Spring đưa ra cho chúng ta các loại collection như sau:

  • dùng để inject list, có thể có các phần tử trùng nhau.
  • dùng để inject set, các phần tử không trùng nhau.
  • dùng để inject collection dạng key-value, trong đó key và value là loại tùy ý.
  • dùng để inject collection dạng key-value, trong đó key và value đều là String.

31. Bean wiring là gì?

Wiring, hoặc là Bean wiring là trường hợp mà các bean được kết hợp lại trong Spring container. Khi wiring bean, Spring container cần biết những bean nào cần và làm thế nào để container sử dụng dependency injection nối tất cả chúng lại với nhau.

32. Bean auto wiring là gì?

Spring container có khả năng autowire quan hệ giữa các bean có mối quan hệ hợp tác với nhau. Spring sẽ giải quyết các mối quan hệ hợp tác bằng cách xem xét nội dụng của BeanFactory với các tag và .

33. Các mode auto wiring

Autowiring có năm mode được sử dụng để hướng dẫn Spring container làm sao autowiring giải quyết dependency injection.

  • no: đây là default setting, bean tham chiếu sẽ được reference rõ ràng khi khai báo.
  • byName: khi autowiring byName, Spring container sẽ cố gắng match giá trị được khai báo trong bean với tên tương tự trong configuration file.
  • byType: khi autowiring bằng data type, Spring container sẽ cố gắng match chính xác với tên của bean trong configuration file. Nếu có nhiều hơn một, fatal exception sẽ được throw ra.
  • constructor: mode này tương tự với byType, nhưng type sẽ apply lên các constructor argument. Nếu không có kết quả nào phù hợp, thì fata exception cũng được throw ra.
  • autodetect: Spring sẽ cố gắng wire bằng cách sử dụng constructor, nếu không có nó sẽ fallback xuống sử dụng byType.

34. Hạn chế của autowiring

Các hạn chế của việc autowiring:

  • Overriding: vẫn có thể định nghĩa các dependencies bằng và việc này sẽ luôn luôn override autowiring.
  • Data types: Không thể autowire những thuộc tính đơn giản như primitive, String và Classes.
  • Confusing: autowiring thì không tường minh, vì thế sử dụng khai báo tường minh có thể là cách khôn ngoan hơn.

35. Có thể inject null hoặc empty String trong Spring hay không?

Có thể.

Spring Annotations

36. Java-based configuration

Java-based configuration cho phép chúng ta viết Spring configuration mà không cần sử dụng XML, thay vào đó chúng ta sử dụng các Java-based annotation. Về Annotation trong Java các bạn có thể tìm đọc bài viết của tôi trong bài Hướng dẫn sử dụng Annotations.

37. Annotation-based configuration

Một phương thức thay thế cho việc setup application bằng XML là chúng ta cung cấp các annotation-based configuration dựa trên bytecode metadata cho việc wiring các component. Thay vì sử dụng XML để mô tả một bean, lập trình viên chuyển các configuration vào trong component class bằng cách sử dụng annotation trong class, method hay field của chính class đó.

38. Làm sao cài đặt autowiring?

Mặc định Spring container sẽ không enable annotation wiring. Để sử dụng annotation-based wiring chúng ta phải enable nó trong Spring configuration bằng tag .

39. @Required annotation

Annotation này đơn giản chỉ ra rằng thuộc tính nào của bean phải được cài đặt tại thời điểm config, thông qua khai báo tường minh hay thông qua autowiring. Nếu những thuộc tính của bean không thể được cài đặt thì container sẽ throw BeanInitializationException.

40. @Autowired annotation

@Autowired annotation cung cấp phương thức wiring cũng như làm thế nào autowiring được hoàn thành. Nó có thể sử dụng autowire bean trong setter method như @Required annotation, trong constructor, trong property hoặc trong method nào đói với một hoặc nhiều argument.

41. @Qualifier annotation

Khi có nhiều hơn một bean với cùng một loại và chỉ có một bean trong số đó cần được wire với một property nào đó, @Qualifier sẽ được sử dụng với @Autowired để giảm thiểu sự nhầm lẫn bằng cách định danh chính xác bean nào được wire.

Trong bài cuối cùng chúng ta sẽ tiếp tục nói về Spring Data Access, Aspect Oriented Programming [AOP], Spring MVC.

Xin chào và hẹn gặp lại.

Đã đăng 02/02/201606/13/2017

Video liên quan

Chủ Đề