Sự khác biệt giữa @Component, @Repository và @Service trong Spring

Có bao giờ các bạn tư hỏi rằng tại sao trong các ứng project Spring hay Spring Boot, các class ở tầng service thì chúng ta đánh dấu nó với @Service annotation, ở tầng giao tiếp với database thì đánh đánh dấu là @Repository, hay ở những class dùng để cấu hình hay được dùng chung ở bất kỳ đâu trong ứng dụng lại được đánh dấu là @Component chưa?

Có thể nhiều bạn chưa để ý, nhưng chúng mang rất nhiều ý nghĩa trong đó đấy, chúng ta sẽ cùng tìm hiểu ngay sau đây.

Phân biệt các layer trong ứng dụng

Trong hầu hết các ứng dụng Spring, chúng ta thường có các layer cơ bản như service chứa code xử lý về bussiness, data access chứa code thao tác với database và presentation dùng để hiển thị giao diện cho người dùng. Hoặc trong Rest API thì ko có presentation mà thay vào đó là controller chẳng hạn.

Ở mỗi layer này đều có các bean cần khởi tạo và đăng ký với ApplicationContext sau đó sẽ được quản lý bởi Spring IoC container. Để phân biệt giữa các bean ở mỗi layer, spring đã cung cấp các annotation @Component, @Service, @Repository được mô tả như sau:

  • @Component – Sử dụng để định nghĩa một khuôn mẫu chung cho toàn bộ dự án. Các bean được tạo ra trong class được đánh dấu với @Component thường sẽ được dùng chung cho toàn bộ dự án hoặc cho một profile cụ thể.
  • @Service – Dùng để đánh dấu các class thuộc tầng service.
  • @Repository – Dùng để đánh dấu các class thuộc tầng giao tiếp với database.

Sự khác nhau giữa @Component, @Service và @Repository

Điểm khác biệt chính giữa 3 annotation này là dùng để phân loại giữa các layer với nhau. Chúng ta cùng tìm hiểu chi tiết hơn ở phần sau.

@Component

Chúng ta sử dụng @Component trên toàn bộ ứng dụng để đánh dấu một class được tạo ra với mục đích là để định nghĩa các bean được quản lý bởi Spring IoC container.

Spring chỉ tìm kiếm và chọn ra những class được đánh dấu với @Component annotaion để khởi tạo và đăng ký với ApplicationContext.

Spring sẽ không tìm kiếm các class được đánh dấu là @Service@Repository, tuy nhiên chúng vẫn sẽ được đăng ký với ApplicationContext bởi chính bản thân chúng đã được đánh dấu với @Component annotation.

Chúng ta có thể thấy @Service annotaiton được định nghĩa như sau

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {

	/**
	 * The value may indicate a suggestion for a logical component name,
	 * to be turned into a Spring bean in case of an autodetected component.
	 * @return the suggested component name, if any (or empty String otherwise)
	 */
	@AliasFor(annotation = Component.class)
	String value() default "";

}

@Repository

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {
    @AliasFor(
        annotation = Component.class
    )
    String value() default "";
}

@Service@Repository là một trường hợp đặc biệt của @Component, về mặt kỹ thuật thì nó tương tự nhau nhưng chúng được sử dụng với mục đích khác nhau.

Do bản thân @Service@Repository đã được đánh dấu với @Component nên chúng sẽ được Spring quét và đăng ký với ApplicationContext, ngoài ra với mỗi annotation này còn có một số chức năng riêng mà chúng ta sẽ tìm hiểu ở phần tiếp theo.

@Repository

Mình xin nhắc lại rằng @Repository là một trường hợp đặc biệt của @Component, bản thân annotation này đã được đánh dấu với @Component, thế nên một class được đánh dấu với @Repository sẽ được khởi tạo và đăng ký với ApplicationContext.

Mục đích sử dụng của @Repository là để áp dụng trên các DAO(Data Access Object) class dùng để thao tác với database.

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.howtodoinjava.demo.model.EmployeeEntity;
  
@Repository
public interface EmployeeRepository
        extends JpaRepository<EmployeeEntity, Long> 
{
    //...
}

@Repository annotation có một vai trò đặc biệt dùng để chuyển đổi các database exception sang Spring-based (Các exception mà Spring có thể hiểu và xử lý được) unchecked exception.

Trong Spring, tất cả các exception liên quan đến data đều được thừa kế từ DataAccessException để bao quát toàn bộ các exception được throw ra bởi JDBC, Hibermate, hay các ORM framework khác.

Lấy ví dụ khi chúng ta làm việc với Hibernate mà không sử dụng Spring Template (ví dụ như JdbcTemplate) để thao tác với database. Trong trường hợp này, nếu Hibernate ném ra một exception thì lúc này spring sẽ không chuyển đổi nó sang Spring-based exception.

Để tự động chuyển đổi các exception sang Spring-based Exception chúng ta cần đánh dấu DAO class với @Repository. Bằng cách này PersistenceExceptionTranslationPostProcessor sẽ thêm một trình biên dịch cho các DAO class và tự động chuyển đổi giữa các exception gốc của database sang các DataAccessException được Spring cung cấp.

@Service

Chúng ta đánh dấu một class với @Service annotation để chỉ ra rằng nó thuộc về tầng service nắm giữ code xử lý business trong đó. Ngoài ra nố không có gì đặc biệt như @Repository.

Kết bài

Như vậy là chúng ta sẽ học được cách phân biệt giữa 3 annotation @Compoent, @Service và @Repository rồi phải không nào. Hy vọng sẽ có ích cho các bạn, giúp các bạn có thể nắm rõ hơn về cách hoạt động của chúng thay vì cứ dùng như một thói quen mà không biết nó có ý nghĩa gì. 

Nguồn tham khảo

https://www.baeldung.com/spring-component-repository-service

https://howtodoinjava.com/spring-boot/repository-annotation/

https://stackoverflow.com/questions/41801512/spring-how-exception-translation-works

1.5 2 votes
Article Rating
Subscribe
Notify of
guest
3 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
3
0
Would love your thoughts, please comment.x
()
x